39dcc119e0272268ae9b4c9d6d0c3f5be300d413
[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 (d->m_echoMode == NoEcho)
1303         pos = 0;
1304     else if (pos > d->m_cursor)
1305         pos += d->preeditAreaText().length();
1306     QTextLine l = d->m_textLayout.lineForTextPosition(pos);
1307     return l.isValid()
1308             ? QRectF(l.cursorToX(pos) - d->hscroll, l.y() - d->vscroll, d->m_cursorWidth, l.height())
1309             : QRectF();
1310 }
1311
1312 /*!
1313     \qmlmethod int QtQuick2::TextInput::positionAt(real x, real y, CursorPosition position = CursorBetweenCharacters)
1314
1315     This function returns the character position at
1316     x and y pixels from the top left  of the textInput. Position 0 is before the
1317     first character, position 1 is after the first character but before the second,
1318     and so on until position text.length, which is after all characters.
1319
1320     This means that for all x values before the first character this function returns 0,
1321     and for all x values after the last character this function returns text.length.  If
1322     the y value is above the text the position will be that of the nearest character on
1323     the first line line and if it is below the text the position of the nearest character
1324     on the last line will be returned.
1325
1326     The cursor position type specifies how the cursor position should be resolved.
1327
1328     \list
1329     \o TextInput.CursorBetweenCharacters - Returns the position between characters that is nearest x.
1330     \o TextInput.CursorOnCharacter - Returns the position before the character that is nearest x.
1331     \endlist
1332 */
1333
1334 void QQuickTextInput::positionAt(QDeclarativeV8Function *args) const
1335 {
1336     Q_D(const QQuickTextInput);
1337
1338     qreal x = 0;
1339     qreal y = 0;
1340     QTextLine::CursorPosition position = QTextLine::CursorBetweenCharacters;
1341
1342     if (args->Length() < 1)
1343         return;
1344
1345     int i = 0;
1346     v8::Local<v8::Value> arg = (*args)[i];
1347     x = arg->NumberValue();
1348
1349     if (++i < args->Length()) {
1350         arg = (*args)[i];
1351         y = arg->NumberValue();
1352     }
1353
1354     if (++i < args->Length()) {
1355         arg = (*args)[i];
1356         position = QTextLine::CursorPosition(arg->Int32Value());
1357     }
1358
1359     int pos = d->positionAt(x, y, position);
1360     const int cursor = d->m_cursor;
1361     if (pos > cursor) {
1362         const int preeditLength = d->preeditAreaText().length();
1363         pos = pos > cursor + preeditLength
1364                 ? pos - preeditLength
1365                 : cursor;
1366     }
1367     args->returnValue(v8::Int32::New(pos));
1368 }
1369
1370 int QQuickTextInputPrivate::positionAt(int x, int y, QTextLine::CursorPosition position) const
1371 {
1372     x += hscroll;
1373     y += vscroll;
1374     QTextLine line = m_textLayout.lineAt(0);
1375     for (int i = 1; i < m_textLayout.lineCount(); ++i) {
1376         QTextLine nextLine = m_textLayout.lineAt(i);
1377
1378         if (y < (line.rect().bottom() + nextLine.y()) / 2)
1379             break;
1380         line = nextLine;
1381     }
1382     return line.isValid() ? line.xToCursor(x, position) : 0;
1383 }
1384
1385 void QQuickTextInput::keyPressEvent(QKeyEvent* ev)
1386 {
1387     Q_D(QQuickTextInput);
1388     // Don't allow MacOSX up/down support, and we don't allow a completer.
1389     bool ignore = (ev->key() == Qt::Key_Up || ev->key() == Qt::Key_Down) && ev->modifiers() == Qt::NoModifier;
1390     if (!ignore && (d->lastSelectionStart == d->lastSelectionEnd) && (ev->key() == Qt::Key_Right || ev->key() == Qt::Key_Left)) {
1391         // Ignore when moving off the end unless there is a selection,
1392         // because then moving will do something (deselect).
1393         int cursorPosition = d->m_cursor;
1394         if (cursorPosition == 0)
1395             ignore = ev->key() == (d->layoutDirection() == Qt::LeftToRight ? Qt::Key_Left : Qt::Key_Right);
1396         if (cursorPosition == text().length())
1397             ignore = ev->key() == (d->layoutDirection() == Qt::LeftToRight ? Qt::Key_Right : Qt::Key_Left);
1398     }
1399     if (ignore) {
1400         ev->ignore();
1401     } else {
1402         d->processKeyEvent(ev);
1403     }
1404     if (!ev->isAccepted())
1405         QQuickImplicitSizeItem::keyPressEvent(ev);
1406 }
1407
1408 void QQuickTextInput::inputMethodEvent(QInputMethodEvent *ev)
1409 {
1410     Q_D(QQuickTextInput);
1411     const bool wasComposing = d->preeditAreaText().length() > 0;
1412     if (d->m_readOnly) {
1413         ev->ignore();
1414     } else {
1415         d->processInputMethodEvent(ev);
1416     }
1417     if (!ev->isAccepted())
1418         QQuickImplicitSizeItem::inputMethodEvent(ev);
1419
1420     if (wasComposing != (d->m_textLayout.preeditAreaText().length() > 0))
1421         emit inputMethodComposingChanged();
1422 }
1423
1424 void QQuickTextInput::mouseDoubleClickEvent(QMouseEvent *event)
1425 {
1426     Q_D(QQuickTextInput);
1427
1428     if (d->selectByMouse && event->button() == Qt::LeftButton) {
1429         d->commitPreedit();
1430         int cursor = d->positionAt(event->localPos());
1431         d->selectWordAtPos(cursor);
1432         event->setAccepted(true);
1433         if (!d->hasPendingTripleClick()) {
1434             d->tripleClickStartPoint = event->localPos().toPoint();
1435             d->tripleClickTimer.start();
1436         }
1437     } else {
1438         if (d->sendMouseEventToInputContext(event))
1439             return;
1440         QQuickImplicitSizeItem::mouseDoubleClickEvent(event);
1441     }
1442 }
1443
1444 void QQuickTextInput::mousePressEvent(QMouseEvent *event)
1445 {
1446     Q_D(QQuickTextInput);
1447
1448     d->pressPos = event->localPos();
1449
1450     if (d->focusOnPress) {
1451         bool hadActiveFocus = hasActiveFocus();
1452         forceActiveFocus();
1453         // re-open input panel on press if already focused
1454         if (hasActiveFocus() && hadActiveFocus && !d->m_readOnly)
1455             openSoftwareInputPanel();
1456     }
1457     if (d->selectByMouse) {
1458         setKeepMouseGrab(false);
1459         d->selectPressed = true;
1460         QPoint distanceVector = d->pressPos.toPoint() - d->tripleClickStartPoint;
1461         if (d->hasPendingTripleClick()
1462             && distanceVector.manhattanLength() < qApp->styleHints()->startDragDistance()) {
1463             event->setAccepted(true);
1464             selectAll();
1465             return;
1466         }
1467     }
1468
1469     if (d->sendMouseEventToInputContext(event))
1470         return;
1471
1472     bool mark = (event->modifiers() & Qt::ShiftModifier) && d->selectByMouse;
1473     int cursor = d->positionAt(event->localPos());
1474     d->moveCursor(cursor, mark);
1475     event->setAccepted(true);
1476 }
1477
1478 void QQuickTextInput::mouseMoveEvent(QMouseEvent *event)
1479 {
1480     Q_D(QQuickTextInput);
1481
1482     if (d->selectPressed) {
1483         if (qAbs(int(event->localPos().x() - d->pressPos.x())) > qApp->styleHints()->startDragDistance())
1484             setKeepMouseGrab(true);
1485
1486         if (d->composeMode()) {
1487             // start selection
1488             int startPos = d->positionAt(d->pressPos);
1489             int currentPos = d->positionAt(event->localPos());
1490             if (startPos != currentPos)
1491                 d->setSelection(startPos, currentPos - startPos);
1492         } else {
1493             moveCursorSelection(d->positionAt(event->localPos()), d->mouseSelectionMode);
1494         }
1495         event->setAccepted(true);
1496     } else {
1497         QQuickImplicitSizeItem::mouseMoveEvent(event);
1498     }
1499 }
1500
1501 void QQuickTextInput::mouseReleaseEvent(QMouseEvent *event)
1502 {
1503     Q_D(QQuickTextInput);
1504     if (d->sendMouseEventToInputContext(event))
1505         return;
1506     if (d->selectPressed) {
1507         d->selectPressed = false;
1508         setKeepMouseGrab(false);
1509     }
1510 #ifndef QT_NO_CLIPBOARD
1511     if (QGuiApplication::clipboard()->supportsSelection()) {
1512         if (event->button() == Qt::LeftButton) {
1513             d->copy(QClipboard::Selection);
1514         } else if (!d->m_readOnly && event->button() == Qt::MidButton) {
1515             d->deselect();
1516             d->insert(QGuiApplication::clipboard()->text(QClipboard::Selection));
1517         }
1518     }
1519 #endif
1520     if (!event->isAccepted())
1521         QQuickImplicitSizeItem::mouseReleaseEvent(event);
1522 }
1523
1524 bool QQuickTextInputPrivate::sendMouseEventToInputContext(QMouseEvent *event)
1525 {
1526 #if !defined QT_NO_IM
1527     if (composeMode()) {
1528         int tmp_cursor = positionAt(event->localPos());
1529         int mousePos = tmp_cursor - m_cursor;
1530         if (mousePos >= 0 && mousePos <= m_textLayout.preeditAreaText().length()) {
1531             if (event->type() == QEvent::MouseButtonRelease) {
1532                 qApp->inputPanel()->invokeAction(QInputPanel::Click, mousePos);
1533             }
1534             return true;
1535         }
1536     }
1537 #else
1538     Q_UNUSED(event);
1539     Q_UNUSED(eventType)
1540 #endif
1541
1542     return false;
1543 }
1544
1545 void QQuickTextInput::mouseUngrabEvent()
1546 {
1547     Q_D(QQuickTextInput);
1548     d->selectPressed = false;
1549     setKeepMouseGrab(false);
1550 }
1551
1552 bool QQuickTextInput::event(QEvent* ev)
1553 {
1554 #ifndef QT_NO_SHORTCUT
1555     Q_D(QQuickTextInput);
1556     if (ev->type() == QEvent::ShortcutOverride) {
1557         if (d->m_readOnly)
1558             return false;
1559         QKeyEvent* ke = static_cast<QKeyEvent*>(ev);
1560         if (ke == QKeySequence::Copy
1561             || ke == QKeySequence::Paste
1562             || ke == QKeySequence::Cut
1563             || ke == QKeySequence::Redo
1564             || ke == QKeySequence::Undo
1565             || ke == QKeySequence::MoveToNextWord
1566             || ke == QKeySequence::MoveToPreviousWord
1567             || ke == QKeySequence::MoveToStartOfDocument
1568             || ke == QKeySequence::MoveToEndOfDocument
1569             || ke == QKeySequence::SelectNextWord
1570             || ke == QKeySequence::SelectPreviousWord
1571             || ke == QKeySequence::SelectStartOfLine
1572             || ke == QKeySequence::SelectEndOfLine
1573             || ke == QKeySequence::SelectStartOfBlock
1574             || ke == QKeySequence::SelectEndOfBlock
1575             || ke == QKeySequence::SelectStartOfDocument
1576             || ke == QKeySequence::SelectAll
1577             || ke == QKeySequence::SelectEndOfDocument) {
1578             ke->accept();
1579         } else if (ke->modifiers() == Qt::NoModifier || ke->modifiers() == Qt::ShiftModifier
1580                    || ke->modifiers() == Qt::KeypadModifier) {
1581             if (ke->key() < Qt::Key_Escape) {
1582                 ke->accept();
1583                 return true;
1584             } else {
1585                 switch (ke->key()) {
1586                 case Qt::Key_Delete:
1587                 case Qt::Key_Home:
1588                 case Qt::Key_End:
1589                 case Qt::Key_Backspace:
1590                 case Qt::Key_Left:
1591                 case Qt::Key_Right:
1592                     return true;
1593                 default:
1594                     break;
1595                 }
1596             }
1597         }
1598     }
1599 #endif
1600
1601     return QQuickImplicitSizeItem::event(ev);
1602 }
1603
1604 void QQuickTextInput::geometryChanged(const QRectF &newGeometry,
1605                                   const QRectF &oldGeometry)
1606 {
1607     Q_D(QQuickTextInput);
1608     if (newGeometry.width() != oldGeometry.width())
1609         d->updateLayout();
1610     updateCursorRectangle();
1611     QQuickImplicitSizeItem::geometryChanged(newGeometry, oldGeometry);
1612 }
1613
1614 void QQuickTextInputPrivate::updateHorizontalScroll()
1615 {
1616     Q_Q(QQuickTextInput);
1617     QTextLine currentLine = m_textLayout.lineForTextPosition(m_cursor + m_preeditCursor);
1618     const int preeditLength = m_textLayout.preeditAreaText().length();
1619     const int width = qMax(0, qFloor(q->width()));
1620     int widthUsed = currentLine.isValid() ? qRound(currentLine.naturalTextWidth()) : 0;
1621     int previousScroll = hscroll;
1622
1623     if (!autoScroll || widthUsed <=  width || m_echoMode == QQuickTextInput::NoEcho) {
1624         hscroll = 0;
1625     } else {
1626         Q_ASSERT(currentLine.isValid());
1627         int cix = qRound(currentLine.cursorToX(m_cursor + preeditLength));
1628         if (cix - hscroll >= width) {
1629             // text doesn't fit, cursor is to the right of br (scroll right)
1630             hscroll = cix - width;
1631         } else if (cix - hscroll < 0 && hscroll < widthUsed) {
1632             // text doesn't fit, cursor is to the left of br (scroll left)
1633             hscroll = cix;
1634         } else if (widthUsed - hscroll < width) {
1635             // text doesn't fit, text document is to the left of br; align
1636             // right
1637             hscroll = widthUsed - width;
1638         }
1639         if (preeditLength > 0) {
1640             // check to ensure long pre-edit text doesn't push the cursor
1641             // off to the left
1642              cix = qRound(currentLine.cursorToX(m_cursor + qMax(0, m_preeditCursor - 1)));
1643              if (cix < hscroll)
1644                  hscroll = cix;
1645         }
1646     }
1647     if (previousScroll != hscroll)
1648         textLayoutDirty = true;
1649 }
1650
1651 void QQuickTextInputPrivate::updateVerticalScroll()
1652 {
1653     Q_Q(QQuickTextInput);
1654     const int preeditLength = m_textLayout.preeditAreaText().length();
1655     const int height = qMax(0, qFloor(q->height()));
1656     int heightUsed = boundingRect.height();
1657     int previousScroll = vscroll;
1658
1659     if (!autoScroll || heightUsed <=  height) {
1660         // text fits in br; use vscroll for alignment
1661         switch (vAlign & ~(Qt::AlignAbsolute|Qt::AlignHorizontal_Mask)) {
1662         case Qt::AlignBottom:
1663             vscroll = heightUsed - height;
1664             break;
1665         case Qt::AlignVCenter:
1666             vscroll = (heightUsed - height) / 2;
1667             break;
1668         default:
1669             // Top
1670             vscroll = 0;
1671             break;
1672         }
1673     } else {
1674         QTextLine currentLine = m_textLayout.lineForTextPosition(m_cursor + preeditLength);
1675         QRectF r = currentLine.isValid() ? currentLine.rect() : QRectF();
1676         int top = qFloor(r.top());
1677         int bottom = qCeil(r.bottom());
1678
1679         if (bottom - vscroll >= height) {
1680             // text doesn't fit, cursor is to the below the br (scroll down)
1681             vscroll = bottom - height;
1682         } else if (top - vscroll < 0 && vscroll < heightUsed) {
1683             // text doesn't fit, cursor is above br (scroll up)
1684             vscroll = top;
1685         } else if (heightUsed - vscroll < height) {
1686             // text doesn't fit, text document is to the left of br; align
1687             // right
1688             vscroll = heightUsed - height;
1689         }
1690         if (preeditLength > 0) {
1691             // check to ensure long pre-edit text doesn't push the cursor
1692             // off the top
1693             currentLine = m_textLayout.lineForTextPosition(m_cursor + qMax(0, m_preeditCursor - 1));
1694             top = currentLine.isValid() ? qRound(currentLine.rect().top()) : 0;
1695             if (top < vscroll)
1696                 vscroll = top;
1697         }
1698     }
1699     if (previousScroll != vscroll)
1700         textLayoutDirty = true;
1701 }
1702
1703 void QQuickTextInput::triggerPreprocess()
1704 {
1705     Q_D(QQuickTextInput);
1706     if (d->updateType == QQuickTextInputPrivate::UpdateNone)
1707         d->updateType = QQuickTextInputPrivate::UpdateOnlyPreprocess;
1708     update();
1709 }
1710
1711 QSGNode *QQuickTextInput::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
1712 {
1713     Q_UNUSED(data);
1714     Q_D(QQuickTextInput);
1715
1716     if (d->updateType != QQuickTextInputPrivate::UpdatePaintNode && oldNode != 0) {
1717         // Update done in preprocess() in the nodes
1718         d->updateType = QQuickTextInputPrivate::UpdateNone;
1719         return oldNode;
1720     }
1721
1722     d->updateType = QQuickTextInputPrivate::UpdateNone;
1723
1724     QQuickTextNode *node = static_cast<QQuickTextNode *>(oldNode);
1725     if (node == 0)
1726         node = new QQuickTextNode(QQuickItemPrivate::get(this)->sceneGraphContext(), this);
1727     d->textNode = node;
1728
1729     if (!d->textLayoutDirty) {
1730         QSGSimpleRectNode *cursorNode = node->cursorNode();
1731         if (cursorNode != 0 && !isReadOnly()) {
1732             cursorNode->setRect(cursorRectangle());
1733
1734             if (!d->cursorVisible || (!d->m_blinkStatus && d->m_blinkPeriod > 0)) {
1735                 d->hideCursor();
1736             } else {
1737                 d->showCursor();
1738             }
1739         }
1740     } else {
1741         node->deleteContent();
1742         node->setMatrix(QMatrix4x4());
1743
1744         QPoint offset = QPoint(0,0);
1745         QFontMetrics fm = QFontMetrics(d->font);
1746         if (d->autoScroll) {
1747             // the y offset is there to keep the baseline constant in case we have script changes in the text.
1748             offset = -QPoint(d->hscroll, d->vscroll + d->m_ascent - fm.ascent());
1749         } else {
1750             offset = -QPoint(d->hscroll, d->vscroll);
1751         }
1752
1753         if (!d->m_textLayout.text().isEmpty() || !d->m_textLayout.preeditAreaText().isEmpty()) {
1754             node->addTextLayout(offset, &d->m_textLayout, d->color,
1755                                 QQuickText::Normal, QColor(),
1756                                 d->selectionColor, d->selectedTextColor,
1757                                 d->selectionStart(),
1758                                 d->selectionEnd() - 1); // selectionEnd() returns first char after
1759                                                                  // selection
1760         }
1761
1762         if (!isReadOnly() && d->cursorItem == 0) {
1763             node->setCursor(cursorRectangle(), d->color);
1764             if (!d->cursorVisible || (!d->m_blinkStatus && d->m_blinkPeriod > 0)) {
1765                 d->hideCursor();
1766             } else {
1767                 d->showCursor();
1768             }
1769         }
1770
1771         d->textLayoutDirty = false;
1772     }
1773
1774     return node;
1775 }
1776
1777 QVariant QQuickTextInput::inputMethodQuery(Qt::InputMethodQuery property) const
1778 {
1779     Q_D(const QQuickTextInput);
1780     switch (property) {
1781     case Qt::ImEnabled:
1782         return QVariant((bool)(flags() & ItemAcceptsInputMethod));
1783     case Qt::ImHints:
1784         return QVariant((int)inputMethodHints());
1785     case Qt::ImCursorRectangle:
1786         return cursorRectangle();
1787     case Qt::ImFont:
1788         return font();
1789     case Qt::ImCursorPosition:
1790         return QVariant(d->m_cursor);
1791     case Qt::ImSurroundingText:
1792         if (d->m_echoMode == PasswordEchoOnEdit && !d->m_passwordEchoEditing) {
1793             return QVariant(displayText());
1794         } else {
1795             return QVariant(d->realText());
1796         }
1797     case Qt::ImCurrentSelection:
1798         return QVariant(selectedText());
1799     case Qt::ImMaximumTextLength:
1800         return QVariant(maxLength());
1801     case Qt::ImAnchorPosition:
1802         if (d->selectionStart() == d->selectionEnd())
1803             return QVariant(d->m_cursor);
1804         else if (d->selectionStart() == d->m_cursor)
1805             return QVariant(d->selectionEnd());
1806         else
1807             return QVariant(d->selectionStart());
1808     default:
1809         return QVariant();
1810     }
1811 }
1812
1813 /*!
1814     \qmlmethod void QtQuick2::TextInput::deselect()
1815
1816     Removes active text selection.
1817 */
1818 void QQuickTextInput::deselect()
1819 {
1820     Q_D(QQuickTextInput);
1821     d->deselect();
1822 }
1823
1824 /*!
1825     \qmlmethod void QtQuick2::TextInput::selectAll()
1826
1827     Causes all text to be selected.
1828 */
1829 void QQuickTextInput::selectAll()
1830 {
1831     Q_D(QQuickTextInput);
1832     d->setSelection(0, text().length());
1833 }
1834
1835 /*!
1836     \qmlmethod void QtQuick2::TextInput::isRightToLeft(int start, int end)
1837
1838     Returns true if the natural reading direction of the editor text
1839     found between positions \a start and \a end is right to left.
1840 */
1841 bool QQuickTextInput::isRightToLeft(int start, int end)
1842 {
1843     if (start > end) {
1844         qmlInfo(this) << "isRightToLeft(start, end) called with the end property being smaller than the start.";
1845         return false;
1846     } else {
1847         return text().mid(start, end - start).isRightToLeft();
1848     }
1849 }
1850
1851 #ifndef QT_NO_CLIPBOARD
1852 /*!
1853     \qmlmethod QtQuick2::TextInput::cut()
1854
1855     Moves the currently selected text to the system clipboard.
1856 */
1857 void QQuickTextInput::cut()
1858 {
1859     Q_D(QQuickTextInput);
1860     d->copy();
1861     d->del();
1862 }
1863
1864 /*!
1865     \qmlmethod QtQuick2::TextInput::copy()
1866
1867     Copies the currently selected text to the system clipboard.
1868 */
1869 void QQuickTextInput::copy()
1870 {
1871     Q_D(QQuickTextInput);
1872     d->copy();
1873 }
1874
1875 /*!
1876     \qmlmethod QtQuick2::TextInput::paste()
1877
1878     Replaces the currently selected text by the contents of the system clipboard.
1879 */
1880 void QQuickTextInput::paste()
1881 {
1882     Q_D(QQuickTextInput);
1883     if (!d->m_readOnly)
1884         d->paste();
1885 }
1886 #endif // QT_NO_CLIPBOARD
1887
1888 /*!
1889     Undoes the last operation if undo is \l {canUndo}{available}. Deselects any
1890     current selection, and updates the selection start to the current cursor
1891     position.
1892 */
1893
1894 void QQuickTextInput::undo()
1895 {
1896     Q_D(QQuickTextInput);
1897     if (!d->m_readOnly) {
1898         d->internalUndo();
1899         d->finishChange(-1, true);
1900     }
1901 }
1902
1903 /*!
1904     Redoes the last operation if redo is \l {canRedo}{available}.
1905 */
1906
1907 void QQuickTextInput::redo()
1908 {
1909     Q_D(QQuickTextInput);
1910     if (!d->m_readOnly) {
1911         d->internalRedo();
1912         d->finishChange();
1913     }
1914 }
1915
1916 /*!
1917     \qmlmethod void QtQuick2::TextInput::insert(int position, string text)
1918
1919     Inserts \a text into the TextInput at position.
1920 */
1921
1922 void QQuickTextInput::insert(int position, const QString &text)
1923 {
1924     Q_D(QQuickTextInput);
1925 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
1926     if (d->m_echoMode == QQuickTextInput::Password)
1927         d->m_passwordEchoTimer.start(qt_passwordEchoDelay, this);
1928 #endif
1929
1930     if (position < 0 || position > d->m_text.length())
1931         return;
1932
1933     const int priorState = d->m_undoState;
1934
1935     QString insertText = text;
1936
1937     if (d->hasSelectedText()) {
1938         d->addCommand(QQuickTextInputPrivate::Command(
1939                 QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
1940     }
1941     if (d->m_maskData) {
1942         insertText = d->maskString(position, insertText);
1943         for (int i = 0; i < insertText.length(); ++i) {
1944             d->addCommand(QQuickTextInputPrivate::Command(
1945                     QQuickTextInputPrivate::DeleteSelection, position + i, d->m_text.at(position + i), -1, -1));
1946             d->addCommand(QQuickTextInputPrivate::Command(
1947                     QQuickTextInputPrivate::Insert, position + i, insertText.at(i), -1, -1));
1948         }
1949         d->m_text.replace(position, insertText.length(), insertText);
1950         if (!insertText.isEmpty())
1951             d->m_textDirty = true;
1952         if (position < d->m_selend && position + insertText.length() > d->m_selstart)
1953             d->m_selDirty = true;
1954     } else {
1955         int remaining = d->m_maxLength - d->m_text.length();
1956         if (remaining != 0) {
1957             insertText = insertText.left(remaining);
1958             d->m_text.insert(position, insertText);
1959             for (int i = 0; i < insertText.length(); ++i)
1960                d->addCommand(QQuickTextInputPrivate::Command(
1961                     QQuickTextInputPrivate::Insert, position + i, insertText.at(i), -1, -1));
1962             if (d->m_cursor >= position)
1963                 d->m_cursor += insertText.length();
1964             if (d->m_selstart >= position)
1965                 d->m_selstart += insertText.length();
1966             if (d->m_selend >= position)
1967                 d->m_selend += insertText.length();
1968             d->m_textDirty = true;
1969             if (position >= d->m_selstart && position <= d->m_selend)
1970                 d->m_selDirty = true;
1971         }
1972     }
1973
1974     d->addCommand(QQuickTextInputPrivate::Command(
1975             QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
1976     d->finishChange(priorState);
1977
1978     if (d->lastSelectionStart != d->lastSelectionEnd) {
1979         if (d->m_selstart != d->lastSelectionStart) {
1980             d->lastSelectionStart = d->m_selstart;
1981             emit selectionStartChanged();
1982         }
1983         if (d->m_selend != d->lastSelectionEnd) {
1984             d->lastSelectionEnd = d->m_selend;
1985             emit selectionEndChanged();
1986         }
1987     }
1988 }
1989
1990 /*!
1991     \qmlmethod string QtQuick2::TextInput::getText(int start, int end)
1992
1993     Removes the section of text that is between the \a start and \a end positions from the TextInput.
1994 */
1995
1996 void QQuickTextInput::remove(int start, int end)
1997 {
1998     Q_D(QQuickTextInput);
1999
2000     start = qBound(0, start, d->m_text.length());
2001     end = qBound(0, end, d->m_text.length());
2002
2003     if (start > end)
2004         qSwap(start, end);
2005     else if (start == end)
2006         return;
2007
2008     if (start < d->m_selend && end > d->m_selstart)
2009         d->m_selDirty = true;
2010
2011     const int priorState = d->m_undoState;
2012
2013     d->addCommand(QQuickTextInputPrivate::Command(
2014             QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
2015
2016     if (start <= d->m_cursor && d->m_cursor < end) {
2017         // cursor is within the selection. Split up the commands
2018         // to be able to restore the correct cursor position
2019         for (int i = d->m_cursor; i >= start; --i) {
2020             d->addCommand(QQuickTextInputPrivate::Command(
2021                     QQuickTextInputPrivate::DeleteSelection, i, d->m_text.at(i), -1, 1));
2022         }
2023         for (int i = end - 1; i > d->m_cursor; --i) {
2024             d->addCommand(QQuickTextInputPrivate::Command(
2025                     QQuickTextInputPrivate::DeleteSelection, i - d->m_cursor + start - 1, d->m_text.at(i), -1, -1));
2026         }
2027     } else {
2028         for (int i = end - 1; i >= start; --i) {
2029             d->addCommand(QQuickTextInputPrivate::Command(
2030                     QQuickTextInputPrivate::RemoveSelection, i, d->m_text.at(i), -1, -1));
2031         }
2032     }
2033     if (d->m_maskData) {
2034         d->m_text.replace(start, end - start,  d->clearString(start, end - start));
2035         for (int i = 0; i < end - start; ++i) {
2036             d->addCommand(QQuickTextInputPrivate::Command(
2037                     QQuickTextInputPrivate::Insert, start + i, d->m_text.at(start + i), -1, -1));
2038         }
2039     } else {
2040         d->m_text.remove(start, end - start);
2041
2042         if (d->m_cursor > start)
2043             d->m_cursor -= qMin(d->m_cursor, end) - start;
2044         if (d->m_selstart > start)
2045             d->m_selstart -= qMin(d->m_selstart, end) - start;
2046         if (d->m_selend > end)
2047             d->m_selend -= qMin(d->m_selend, end) - start;
2048     }
2049     d->addCommand(QQuickTextInputPrivate::Command(
2050             QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));
2051
2052     d->m_textDirty = true;
2053     d->finishChange(priorState);
2054
2055     if (d->lastSelectionStart != d->lastSelectionEnd) {
2056         if (d->m_selstart != d->lastSelectionStart) {
2057             d->lastSelectionStart = d->m_selstart;
2058             emit selectionStartChanged();
2059         }
2060         if (d->m_selend != d->lastSelectionEnd) {
2061             d->lastSelectionEnd = d->m_selend;
2062             emit selectionEndChanged();
2063         }
2064     }
2065 }
2066
2067
2068 /*!
2069     \qmlmethod void QtQuick2::TextInput::selectWord()
2070
2071     Causes the word closest to the current cursor position to be selected.
2072 */
2073 void QQuickTextInput::selectWord()
2074 {
2075     Q_D(QQuickTextInput);
2076     d->selectWordAtPos(d->m_cursor);
2077 }
2078
2079 /*!
2080     \qmlproperty bool QtQuick2::TextInput::smooth
2081
2082     This property holds whether the text is smoothly scaled or transformed.
2083
2084     Smooth filtering gives better visual quality, but is slower.  If
2085     the item is displayed at its natural size, this property has no visual or
2086     performance effect.
2087
2088     \note Generally scaling artifacts are only visible if the item is stationary on
2089     the screen.  A common pattern when animating an item is to disable smooth
2090     filtering at the beginning of the animation and reenable it at the conclusion.
2091 */
2092
2093 /*!
2094    \qmlproperty string QtQuick2::TextInput::passwordCharacter
2095
2096    This is the character displayed when echoMode is set to Password or
2097    PasswordEchoOnEdit. By default it is an asterisk.
2098
2099    If this property is set to a string with more than one character,
2100    the first character is used. If the string is empty, the value
2101    is ignored and the property is not set.
2102 */
2103 QString QQuickTextInput::passwordCharacter() const
2104 {
2105     Q_D(const QQuickTextInput);
2106     return QString(d->m_passwordCharacter);
2107 }
2108
2109 void QQuickTextInput::setPasswordCharacter(const QString &str)
2110 {
2111     Q_D(QQuickTextInput);
2112     if (str.length() < 1)
2113         return;
2114     d->m_passwordCharacter = str.constData()[0];
2115     if (d->m_echoMode == Password || d->m_echoMode == PasswordEchoOnEdit)
2116         d->updateDisplayText();
2117     emit passwordCharacterChanged();
2118 }
2119
2120 /*!
2121    \qmlproperty string QtQuick2::TextInput::displayText
2122
2123    This is the text displayed in the TextInput.
2124
2125    If \l echoMode is set to TextInput::Normal, this holds the
2126    same value as the TextInput::text property. Otherwise,
2127    this property holds the text visible to the user, while
2128    the \l text property holds the actual entered text.
2129 */
2130 QString QQuickTextInput::displayText() const
2131 {
2132     Q_D(const QQuickTextInput);
2133     return d->m_textLayout.text();
2134 }
2135
2136 /*!
2137     \qmlproperty bool QtQuick2::TextInput::selectByMouse
2138
2139     Defaults to false.
2140
2141     If true, the user can use the mouse to select text in some
2142     platform-specific way. Note that for some platforms this may
2143     not be an appropriate interaction (eg. may conflict with how
2144     the text needs to behave inside a Flickable.
2145 */
2146 bool QQuickTextInput::selectByMouse() const
2147 {
2148     Q_D(const QQuickTextInput);
2149     return d->selectByMouse;
2150 }
2151
2152 void QQuickTextInput::setSelectByMouse(bool on)
2153 {
2154     Q_D(QQuickTextInput);
2155     if (d->selectByMouse != on) {
2156         d->selectByMouse = on;
2157         emit selectByMouseChanged(on);
2158     }
2159 }
2160
2161 /*!
2162     \qmlproperty enum QtQuick2::TextInput::mouseSelectionMode
2163
2164     Specifies how text should be selected using a mouse.
2165
2166     \list
2167     \o TextInput.SelectCharacters - The selection is updated with individual characters. (Default)
2168     \o TextInput.SelectWords - The selection is updated with whole words.
2169     \endlist
2170
2171     This property only applies when \l selectByMouse is true.
2172 */
2173
2174 QQuickTextInput::SelectionMode QQuickTextInput::mouseSelectionMode() const
2175 {
2176     Q_D(const QQuickTextInput);
2177     return d->mouseSelectionMode;
2178 }
2179
2180 void QQuickTextInput::setMouseSelectionMode(SelectionMode mode)
2181 {
2182     Q_D(QQuickTextInput);
2183     if (d->mouseSelectionMode != mode) {
2184         d->mouseSelectionMode = mode;
2185         emit mouseSelectionModeChanged(mode);
2186     }
2187 }
2188
2189 /*!
2190     \qmlproperty bool QtQuick2::TextInput::persistentSelection
2191
2192     Whether the TextInput should keep its selection when it loses active focus to another
2193     item in the scene. By default this is set to false;
2194 */
2195
2196 bool QQuickTextInput::persistentSelection() const
2197 {
2198     Q_D(const QQuickTextInput);
2199     return d->persistentSelection;
2200 }
2201
2202 void QQuickTextInput::setPersistentSelection(bool on)
2203 {
2204     Q_D(QQuickTextInput);
2205     if (d->persistentSelection == on)
2206         return;
2207     d->persistentSelection = on;
2208     emit persistentSelectionChanged();
2209 }
2210
2211 /*!
2212     \qmlproperty bool QtQuick2::TextInput::canPaste
2213
2214     Returns true if the TextInput is writable and the content of the clipboard is
2215     suitable for pasting into the TextInput.
2216 */
2217 bool QQuickTextInput::canPaste() const
2218 {
2219     Q_D(const QQuickTextInput);
2220     if (!d->canPasteValid) {
2221         if (const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData())
2222             const_cast<QQuickTextInputPrivate *>(d)->canPaste = !d->m_readOnly && mimeData->hasText();
2223         const_cast<QQuickTextInputPrivate *>(d)->canPasteValid = true;
2224     }
2225     return d->canPaste;
2226 }
2227
2228 /*!
2229     \qmlproperty bool QtQuick2::TextInput::canUndo
2230
2231     Returns true if the TextInput is writable and there are previous operations
2232     that can be undone.
2233 */
2234
2235 bool QQuickTextInput::canUndo() const
2236 {
2237     Q_D(const QQuickTextInput);
2238     return d->canUndo;
2239 }
2240
2241 /*!
2242     \qmlproperty bool QtQuick2::TextInput::canRedo
2243
2244     Returns true if the TextInput is writable and there are \l {undo}{undone}
2245     operations that can be redone.
2246 */
2247
2248 bool QQuickTextInput::canRedo() const
2249 {
2250     Q_D(const QQuickTextInput);
2251     return d->canRedo;
2252 }
2253
2254 void QQuickTextInput::moveCursorSelection(int position)
2255 {
2256     Q_D(QQuickTextInput);
2257     d->moveCursor(position, true);
2258 }
2259
2260 /*!
2261     \qmlmethod void QtQuick2::TextInput::moveCursorSelection(int position, SelectionMode mode = TextInput.SelectCharacters)
2262
2263     Moves the cursor to \a position and updates the selection according to the optional \a mode
2264     parameter.  (To only move the cursor, set the \l cursorPosition property.)
2265
2266     When this method is called it additionally sets either the
2267     selectionStart or the selectionEnd (whichever was at the previous cursor position)
2268     to the specified position. This allows you to easily extend and contract the selected
2269     text range.
2270
2271     The selection mode specifies whether the selection is updated on a per character or a per word
2272     basis.  If not specified the selection mode will default to TextInput.SelectCharacters.
2273
2274     \list
2275     \o TextInput.SelectCharacters - Sets either the selectionStart or selectionEnd (whichever was at
2276     the previous cursor position) to the specified position.
2277     \o TextInput.SelectWords - Sets the selectionStart and selectionEnd to include all
2278     words between the specified position and the previous cursor position.  Words partially in the
2279     range are included.
2280     \endlist
2281
2282     For example, take this sequence of calls:
2283
2284     \code
2285         cursorPosition = 5
2286         moveCursorSelection(9, TextInput.SelectCharacters)
2287         moveCursorSelection(7, TextInput.SelectCharacters)
2288     \endcode
2289
2290     This moves the cursor to position 5, extend the selection end from 5 to 9
2291     and then retract the selection end from 9 to 7, leaving the text from position 5 to 7
2292     selected (the 6th and 7th characters).
2293
2294     The same sequence with TextInput.SelectWords will extend the selection start to a word boundary
2295     before or on position 5 and extend the selection end to a word boundary on or past position 9.
2296 */
2297 void QQuickTextInput::moveCursorSelection(int pos, SelectionMode mode)
2298 {
2299     Q_D(QQuickTextInput);
2300
2301     if (mode == SelectCharacters) {
2302         d->moveCursor(pos, true);
2303     } else if (pos != d->m_cursor){
2304         const int cursor = d->m_cursor;
2305         int anchor;
2306         if (!d->hasSelectedText())
2307             anchor = d->m_cursor;
2308         else if (d->selectionStart() == d->m_cursor)
2309             anchor = d->selectionEnd();
2310         else
2311             anchor = d->selectionStart();
2312
2313         if (anchor < pos || (anchor == pos && cursor < pos)) {
2314             const QString text = this->text();
2315             QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
2316             finder.setPosition(anchor);
2317
2318             const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
2319             if (anchor < text.length() && (!(reasons & QTextBoundaryFinder::StartWord)
2320                     || ((reasons & QTextBoundaryFinder::EndWord) && anchor > cursor))) {
2321                 finder.toPreviousBoundary();
2322             }
2323             anchor = finder.position() != -1 ? finder.position() : 0;
2324
2325             finder.setPosition(pos);
2326             if (pos > 0 && !finder.boundaryReasons())
2327                 finder.toNextBoundary();
2328             const int cursor = finder.position() != -1 ? finder.position() : text.length();
2329
2330             d->setSelection(anchor, cursor - anchor);
2331         } else if (anchor > pos || (anchor == pos && cursor > pos)) {
2332             const QString text = this->text();
2333             QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
2334             finder.setPosition(anchor);
2335
2336             const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
2337             if (anchor > 0 && (!(reasons & QTextBoundaryFinder::EndWord)
2338                     || ((reasons & QTextBoundaryFinder::StartWord) && anchor < cursor))) {
2339                 finder.toNextBoundary();
2340             }
2341
2342             anchor = finder.position() != -1 ? finder.position() : text.length();
2343
2344             finder.setPosition(pos);
2345             if (pos < text.length() && !finder.boundaryReasons())
2346                  finder.toPreviousBoundary();
2347             const int cursor = finder.position() != -1 ? finder.position() : 0;
2348
2349             d->setSelection(anchor, cursor - anchor);
2350         }
2351     }
2352 }
2353
2354 /*!
2355     \qmlmethod void QtQuick2::TextInput::openSoftwareInputPanel()
2356
2357     Opens software input panels like virtual keyboards for typing, useful for
2358     customizing when you want the input keyboard to be shown and hidden in
2359     your application.
2360
2361     By default the opening of input panels follows the platform style. Input panels are
2362     always closed if no editor has active focus.
2363
2364     You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
2365     and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
2366     the behavior you want.
2367
2368     Only relevant on platforms, which provide virtual keyboards.
2369
2370     \qml
2371         import QtQuick 2.0
2372         TextInput {
2373             id: textInput
2374             text: "Hello world!"
2375             activeFocusOnPress: false
2376             MouseArea {
2377                 anchors.fill: parent
2378                 onClicked: {
2379                     if (!textInput.activeFocus) {
2380                         textInput.forceActiveFocus()
2381                         textInput.openSoftwareInputPanel();
2382                     } else {
2383                         textInput.focus = false;
2384                     }
2385                 }
2386                 onPressAndHold: textInput.closeSoftwareInputPanel();
2387             }
2388         }
2389     \endqml
2390 */
2391 void QQuickTextInput::openSoftwareInputPanel()
2392 {
2393     if (qGuiApp)
2394         qGuiApp->inputPanel()->show();
2395 }
2396
2397 /*!
2398     \qmlmethod void QtQuick2::TextInput::closeSoftwareInputPanel()
2399
2400     Closes a software input panel like a virtual keyboard shown on the screen, useful
2401     for customizing when you want the input keyboard to be shown and hidden in
2402     your application.
2403
2404     By default the opening of input panels follows the platform style. Input panels are
2405     always closed if no editor has active focus.
2406
2407     You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
2408     and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
2409     the behavior you want.
2410
2411     Only relevant on platforms, which provide virtual keyboards.
2412
2413     \qml
2414         import QtQuick 2.0
2415         TextInput {
2416             id: textInput
2417             text: "Hello world!"
2418             activeFocusOnPress: false
2419             MouseArea {
2420                 anchors.fill: parent
2421                 onClicked: {
2422                     if (!textInput.activeFocus) {
2423                         textInput.forceActiveFocus();
2424                         textInput.openSoftwareInputPanel();
2425                     } else {
2426                         textInput.focus = false;
2427                     }
2428                 }
2429                 onPressAndHold: textInput.closeSoftwareInputPanel();
2430             }
2431         }
2432     \endqml
2433 */
2434 void QQuickTextInput::closeSoftwareInputPanel()
2435 {
2436     if (qGuiApp)
2437         qGuiApp->inputPanel()->hide();
2438 }
2439
2440 void QQuickTextInput::focusInEvent(QFocusEvent *event)
2441 {
2442     Q_D(const QQuickTextInput);
2443     if (d->focusOnPress && !d->m_readOnly)
2444         openSoftwareInputPanel();
2445     QQuickImplicitSizeItem::focusInEvent(event);
2446 }
2447
2448 void QQuickTextInput::itemChange(ItemChange change, const ItemChangeData &value)
2449 {
2450     Q_D(QQuickTextInput);
2451     if (change == ItemActiveFocusHasChanged) {
2452         bool hasFocus = value.boolValue;
2453         d->focused = hasFocus;
2454         setCursorVisible(hasFocus); // ### refactor:  && d->canvas && d->canvas->hasFocus()
2455 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
2456         if (!hasFocus && (d->m_passwordEchoEditing || d->m_passwordEchoTimer.isActive())) {
2457 #else
2458         if (!hasFocus && d->m_passwordEchoEditing) {
2459 #endif
2460             d->updatePasswordEchoEditing(false);//QQuickTextInputPrivate sets it on key events, but doesn't deal with focus events
2461         }
2462
2463         if (!hasFocus) {
2464             d->commitPreedit();
2465             if (!d->persistentSelection)
2466                 d->deselect();
2467             disconnect(qApp->inputPanel(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
2468                        this, SLOT(q_updateAlignment()));
2469         } else {
2470             q_updateAlignment();
2471             connect(qApp->inputPanel(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
2472                     this, SLOT(q_updateAlignment()));
2473         }
2474     }
2475     QQuickItem::itemChange(change, value);
2476 }
2477
2478 /*!
2479     \qmlproperty bool QtQuick2::TextInput::inputMethodComposing
2480
2481
2482     This property holds whether the TextInput has partial text input from an
2483     input method.
2484
2485     While it is composing an input method may rely on mouse or key events from
2486     the TextInput to edit or commit the partial text.  This property can be
2487     used to determine when to disable events handlers that may interfere with
2488     the correct operation of an input method.
2489 */
2490 bool QQuickTextInput::isInputMethodComposing() const
2491 {
2492     Q_D(const QQuickTextInput);
2493     return d->preeditAreaText().length() > 0;
2494 }
2495
2496 void QQuickTextInputPrivate::init()
2497 {
2498     Q_Q(QQuickTextInput);
2499     q->setSmooth(smooth);
2500     q->setAcceptedMouseButtons(Qt::LeftButton);
2501     q->setFlag(QQuickItem::ItemAcceptsInputMethod);
2502     q->setFlag(QQuickItem::ItemHasContents);
2503 #ifndef QT_NO_CLIPBOARD
2504     q->connect(QGuiApplication::clipboard(), SIGNAL(dataChanged()),
2505             q, SLOT(q_canPasteChanged()));
2506 #endif // QT_NO_CLIPBOARD
2507
2508     lastSelectionStart = 0;
2509     lastSelectionEnd = 0;
2510     selectedTextColor = m_palette.color(QPalette::HighlightedText);
2511     selectionColor = m_palette.color(QPalette::Highlight);
2512     determineHorizontalAlignment();
2513
2514     if (!qmlDisableDistanceField()) {
2515         QTextOption option = m_textLayout.textOption();
2516         option.setUseDesignMetrics(true);
2517         m_textLayout.setTextOption(option);
2518     }
2519 }
2520
2521 void QQuickTextInput::updateCursorRectangle()
2522 {
2523     Q_D(QQuickTextInput);
2524     if (!isComponentComplete())
2525         return;
2526
2527     d->updateHorizontalScroll();
2528     d->updateVerticalScroll();
2529     d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
2530     update();
2531     emit cursorRectangleChanged();
2532     if (d->cursorItem) {
2533         QRectF r = cursorRectangle();
2534         d->cursorItem->setPos(r.topLeft());
2535         d->cursorItem->setHeight(r.height());
2536     }
2537     updateInputMethod(Qt::ImCursorRectangle);
2538 }
2539
2540 void QQuickTextInput::selectionChanged()
2541 {
2542     Q_D(QQuickTextInput);
2543     d->textLayoutDirty = true; //TODO: Only update rect in selection
2544     d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
2545     update();
2546     emit selectedTextChanged();
2547
2548     if (d->lastSelectionStart != d->selectionStart()) {
2549         d->lastSelectionStart = d->selectionStart();
2550         if (d->lastSelectionStart == -1)
2551             d->lastSelectionStart = d->m_cursor;
2552         emit selectionStartChanged();
2553     }
2554     if (d->lastSelectionEnd != d->selectionEnd()) {
2555         d->lastSelectionEnd = d->selectionEnd();
2556         if (d->lastSelectionEnd == -1)
2557             d->lastSelectionEnd = d->m_cursor;
2558         emit selectionEndChanged();
2559     }
2560 }
2561
2562 void QQuickTextInputPrivate::showCursor()
2563 {
2564     if (textNode != 0 && textNode->cursorNode() != 0)
2565         textNode->cursorNode()->setColor(color);
2566 }
2567
2568 void QQuickTextInputPrivate::hideCursor()
2569 {
2570     if (textNode != 0 && textNode->cursorNode() != 0)
2571         textNode->cursorNode()->setColor(QColor(0, 0, 0, 0));
2572 }
2573
2574 QRectF QQuickTextInput::boundingRect() const
2575 {
2576     Q_D(const QQuickTextInput);
2577
2578     int cursorWidth = d->cursorItem ? d->cursorItem->width() : d->m_cursorWidth;
2579
2580     // Could include font max left/right bearings to either side of rectangle.
2581     QRectF r = QQuickImplicitSizeItem::boundingRect();
2582     r.setRight(r.right() + cursorWidth);
2583     return r;
2584 }
2585
2586 void QQuickTextInput::q_canPasteChanged()
2587 {
2588     Q_D(QQuickTextInput);
2589     bool old = d->canPaste;
2590 #ifndef QT_NO_CLIPBOARD
2591     if (const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData())
2592         d->canPaste = !d->m_readOnly && mimeData->hasText();
2593     else
2594         d->canPaste = false;
2595 #endif
2596
2597     bool changed = d->canPaste != old || !d->canPasteValid;
2598     d->canPasteValid = true;
2599     if (changed)
2600         emit canPasteChanged();
2601
2602 }
2603
2604 void QQuickTextInput::q_updateAlignment()
2605 {
2606     Q_D(QQuickTextInput);
2607     if (d->determineHorizontalAlignment()) {
2608         d->updateLayout();
2609         updateCursorRectangle();
2610     }
2611 }
2612
2613 // ### these should come from QStyleHints
2614 const int textCursorWidth = 1;
2615 const bool fullWidthSelection = true;
2616
2617 /*!
2618     \internal
2619
2620     Updates the display text based of the current edit text
2621     If the text has changed will emit displayTextChanged()
2622 */
2623 void QQuickTextInputPrivate::updateDisplayText(bool forceUpdate)
2624 {
2625     QString orig = m_textLayout.text();
2626     QString str;
2627     if (m_echoMode == QQuickTextInput::NoEcho)
2628         str = QString::fromLatin1("");
2629     else
2630         str = m_text;
2631
2632     if (m_echoMode == QQuickTextInput::Password) {
2633          str.fill(m_passwordCharacter);
2634 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
2635         if (m_passwordEchoTimer.isActive() && m_cursor > 0 && m_cursor <= m_text.length()) {
2636             int cursor = m_cursor - 1;
2637             QChar uc = m_text.at(cursor);
2638             str[cursor] = uc;
2639             if (cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
2640                 // second half of a surrogate, check if we have the first half as well,
2641                 // if yes restore both at once
2642                 uc = m_text.at(cursor - 1);
2643                 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00)
2644                     str[cursor - 1] = uc;
2645             }
2646         }
2647 #endif
2648     } else if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
2649         str.fill(m_passwordCharacter);
2650     }
2651
2652     // replace certain non-printable characters with spaces (to avoid
2653     // drawing boxes when using fonts that don't have glyphs for such
2654     // characters)
2655     QChar* uc = str.data();
2656     for (int i = 0; i < (int)str.length(); ++i) {
2657         if ((uc[i] < 0x20 && uc[i] != 0x09)
2658             || uc[i] == QChar::LineSeparator
2659             || uc[i] == QChar::ParagraphSeparator
2660             || uc[i] == QChar::ObjectReplacementCharacter)
2661             uc[i] = QChar(0x0020);
2662     }
2663
2664     if (str != orig || forceUpdate) {
2665         m_textLayout.setText(str);
2666         updateLayout(); // polish?
2667         emit q_func()->displayTextChanged();
2668     }
2669 }
2670
2671 void QQuickTextInputPrivate::updateLayout()
2672 {
2673     Q_Q(QQuickTextInput);
2674
2675     if (!q->isComponentComplete())
2676         return;
2677
2678     QTextOption option = m_textLayout.textOption();
2679     option.setTextDirection(layoutDirection());
2680     option.setFlags(QTextOption::IncludeTrailingSpaces);
2681     option.setWrapMode(QTextOption::WrapMode(wrapMode));
2682     option.setAlignment(Qt::Alignment(q->effectiveHAlign()));
2683     m_textLayout.setTextOption(option);
2684     m_textLayout.setFont(font);
2685
2686     boundingRect = QRectF();
2687     m_textLayout.beginLayout();
2688     QTextLine line = m_textLayout.createLine();
2689     qreal lineWidth = q->widthValid() ? q->width() : INT_MAX;
2690     qreal height = 0;
2691     QTextLine firstLine = line;
2692     do {
2693         line.setLineWidth(lineWidth);
2694         line.setPosition(QPointF(line.position().x(), height));
2695         boundingRect = boundingRect.united(line.naturalTextRect());
2696
2697         height += line.height();
2698         line = m_textLayout.createLine();
2699     } while (line.isValid());
2700     m_textLayout.endLayout();
2701
2702     option.setWrapMode(QTextOption::NoWrap);
2703     m_textLayout.setTextOption(option);
2704
2705     m_ascent = qRound(firstLine.ascent());
2706     textLayoutDirty = true;
2707
2708     updateType = UpdatePaintNode;
2709     q->update();
2710     q->setImplicitSize(qCeil(boundingRect.width()), qCeil(boundingRect.height()));
2711
2712 }
2713
2714 #ifndef QT_NO_CLIPBOARD
2715 /*!
2716     \internal
2717
2718     Copies the currently selected text into the clipboard using the given
2719     \a mode.
2720
2721     \note If the echo mode is set to a mode other than Normal then copy
2722     will not work.  This is to prevent using copy as a method of bypassing
2723     password features of the line control.
2724 */
2725 void QQuickTextInputPrivate::copy(QClipboard::Mode mode) const
2726 {
2727     QString t = selectedText();
2728     if (!t.isEmpty() && m_echoMode == QQuickTextInput::Normal) {
2729         QGuiApplication::clipboard()->setText(t, mode);
2730     }
2731 }
2732
2733 /*!
2734     \internal
2735
2736     Inserts the text stored in the application clipboard into the line
2737     control.
2738
2739     \sa insert()
2740 */
2741 void QQuickTextInputPrivate::paste(QClipboard::Mode clipboardMode)
2742 {
2743     QString clip = QGuiApplication::clipboard()->text(clipboardMode);
2744     if (!clip.isEmpty() || hasSelectedText()) {
2745         separate(); //make it a separate undo/redo command
2746         insert(clip);
2747         separate();
2748     }
2749 }
2750
2751 #endif // !QT_NO_CLIPBOARD
2752
2753 /*!
2754     \internal
2755
2756     Exits preedit mode and commits parts marked as tentative commit
2757 */
2758 void QQuickTextInputPrivate::commitPreedit()
2759 {
2760     if (!composeMode())
2761         return;
2762
2763     qApp->inputPanel()->reset();
2764
2765     if (!m_tentativeCommit.isEmpty()) {
2766         internalInsert(m_tentativeCommit);
2767         m_tentativeCommit.clear();
2768         finishChange(-1, true/*not used, not documented*/, false);
2769     }
2770
2771     m_preeditCursor = 0;
2772     m_textLayout.setPreeditArea(-1, QString());
2773     m_textLayout.clearAdditionalFormats();
2774     updateLayout();
2775 }
2776
2777 /*!
2778     \internal
2779
2780     Handles the behavior for the backspace key or function.
2781     Removes the current selection if there is a selection, otherwise
2782     removes the character prior to the cursor position.
2783
2784     \sa del()
2785 */
2786 void QQuickTextInputPrivate::backspace()
2787 {
2788     int priorState = m_undoState;
2789     if (hasSelectedText()) {
2790         removeSelectedText();
2791     } else if (m_cursor) {
2792             --m_cursor;
2793             if (m_maskData)
2794                 m_cursor = prevMaskBlank(m_cursor);
2795             QChar uc = m_text.at(m_cursor);
2796             if (m_cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
2797                 // second half of a surrogate, check if we have the first half as well,
2798                 // if yes delete both at once
2799                 uc = m_text.at(m_cursor - 1);
2800                 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00) {
2801                     internalDelete(true);
2802                     --m_cursor;
2803                 }
2804             }
2805             internalDelete(true);
2806     }
2807     finishChange(priorState);
2808 }
2809
2810 /*!
2811     \internal
2812
2813     Handles the behavior for the delete key or function.
2814     Removes the current selection if there is a selection, otherwise
2815     removes the character after the cursor position.
2816
2817     \sa del()
2818 */
2819 void QQuickTextInputPrivate::del()
2820 {
2821     int priorState = m_undoState;
2822     if (hasSelectedText()) {
2823         removeSelectedText();
2824     } else {
2825         int n = m_textLayout.nextCursorPosition(m_cursor) - m_cursor;
2826         while (n--)
2827             internalDelete();
2828     }
2829     finishChange(priorState);
2830 }
2831
2832 /*!
2833     \internal
2834
2835     Inserts the given \a newText at the current cursor position.
2836     If there is any selected text it is removed prior to insertion of
2837     the new text.
2838 */
2839 void QQuickTextInputPrivate::insert(const QString &newText)
2840 {
2841     int priorState = m_undoState;
2842     removeSelectedText();
2843     internalInsert(newText);
2844     finishChange(priorState);
2845 }
2846
2847 /*!
2848     \internal
2849
2850     Clears the line control text.
2851 */
2852 void QQuickTextInputPrivate::clear()
2853 {
2854     int priorState = m_undoState;
2855     m_selstart = 0;
2856     m_selend = m_text.length();
2857     removeSelectedText();
2858     separate();
2859     finishChange(priorState, /*update*/false, /*edited*/false);
2860 }
2861
2862 /*!
2863     \internal
2864
2865     Sets \a length characters from the given \a start position as selected.
2866     The given \a start position must be within the current text for
2867     the line control.  If \a length characters cannot be selected, then
2868     the selection will extend to the end of the current text.
2869 */
2870 void QQuickTextInputPrivate::setSelection(int start, int length)
2871 {
2872     Q_Q(QQuickTextInput);
2873     commitPreedit();
2874
2875     if (start < 0 || start > (int)m_text.length()){
2876         qWarning("QQuickTextInputPrivate::setSelection: Invalid start position");
2877         return;
2878     }
2879
2880     if (length > 0) {
2881         if (start == m_selstart && start + length == m_selend && m_cursor == m_selend)
2882             return;
2883         m_selstart = start;
2884         m_selend = qMin(start + length, (int)m_text.length());
2885         m_cursor = m_selend;
2886     } else if (length < 0){
2887         if (start == m_selend && start + length == m_selstart && m_cursor == m_selstart)
2888             return;
2889         m_selstart = qMax(start + length, 0);
2890         m_selend = start;
2891         m_cursor = m_selstart;
2892     } else if (m_selstart != m_selend) {
2893         m_selstart = 0;
2894         m_selend = 0;
2895         m_cursor = start;
2896     } else {
2897         m_cursor = start;
2898         emitCursorPositionChanged();
2899         return;
2900     }
2901     emit q->selectionChanged();
2902     emitCursorPositionChanged();
2903     q->updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorPosition
2904                         | Qt::ImCursorPosition | Qt::ImCurrentSelection);
2905 }
2906
2907 /*!
2908     \internal
2909
2910     Initializes the line control with a starting text value of \a txt.
2911 */
2912 void QQuickTextInputPrivate::init(const QString &txt)
2913 {
2914     m_text = txt;
2915
2916     updateDisplayText();
2917     m_cursor = m_text.length();
2918 }
2919
2920 /*!
2921     \internal
2922
2923     Sets the password echo editing to \a editing.  If password echo editing
2924     is true, then the text of the password is displayed even if the echo
2925     mode is set to QLineEdit::PasswordEchoOnEdit.  Password echoing editing
2926     does not affect other echo modes.
2927 */
2928 void QQuickTextInputPrivate::updatePasswordEchoEditing(bool editing)
2929 {
2930     cancelPasswordEchoTimer();
2931     m_passwordEchoEditing = editing;
2932     updateDisplayText();
2933 }
2934
2935 /*!
2936     \internal
2937
2938     Fixes the current text so that it is valid given any set validators.
2939
2940     Returns true if the text was changed.  Otherwise returns false.
2941 */
2942 bool QQuickTextInputPrivate::fixup() // this function assumes that validate currently returns != Acceptable
2943 {
2944 #ifndef QT_NO_VALIDATOR
2945     if (m_validator) {
2946         QString textCopy = m_text;
2947         int cursorCopy = m_cursor;
2948         m_validator->fixup(textCopy);
2949         if (m_validator->validate(textCopy, cursorCopy) == QValidator::Acceptable) {
2950             if (textCopy != m_text || cursorCopy != m_cursor)
2951                 internalSetText(textCopy, cursorCopy);
2952             return true;
2953         }
2954     }
2955 #endif
2956     return false;
2957 }
2958
2959 /*!
2960     \internal
2961
2962     Moves the cursor to the given position \a pos.   If \a mark is true will
2963     adjust the currently selected text.
2964 */
2965 void QQuickTextInputPrivate::moveCursor(int pos, bool mark)
2966 {
2967     Q_Q(QQuickTextInput);
2968     commitPreedit();
2969
2970     if (pos != m_cursor) {
2971         separate();
2972         if (m_maskData)
2973             pos = pos > m_cursor ? nextMaskBlank(pos) : prevMaskBlank(pos);
2974     }
2975     if (mark) {
2976         int anchor;
2977         if (m_selend > m_selstart && m_cursor == m_selstart)
2978             anchor = m_selend;
2979         else if (m_selend > m_selstart && m_cursor == m_selend)
2980             anchor = m_selstart;
2981         else
2982             anchor = m_cursor;
2983         m_selstart = qMin(anchor, pos);
2984         m_selend = qMax(anchor, pos);
2985     } else {
2986         internalDeselect();
2987     }
2988     m_cursor = pos;
2989     if (mark || m_selDirty) {
2990         m_selDirty = false;
2991         emit q->selectionChanged();
2992     }
2993     emitCursorPositionChanged();
2994     q->updateInputMethod();
2995 }
2996
2997 /*!
2998     \internal
2999
3000     Applies the given input method event \a event to the text of the line
3001     control
3002 */
3003 void QQuickTextInputPrivate::processInputMethodEvent(QInputMethodEvent *event)
3004 {
3005     Q_Q(QQuickTextInput);
3006
3007     int priorState = -1;
3008     bool isGettingInput = !event->commitString().isEmpty()
3009             || event->preeditString() != preeditAreaText()
3010             || event->replacementLength() > 0;
3011     bool cursorPositionChanged = false;
3012     bool selectionChange = false;
3013     m_preeditDirty = event->preeditString() != preeditAreaText();
3014
3015     if (isGettingInput) {
3016         // If any text is being input, remove selected text.
3017         priorState = m_undoState;
3018         if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
3019             updatePasswordEchoEditing(true);
3020             m_selstart = 0;
3021             m_selend = m_text.length();
3022         }
3023         removeSelectedText();
3024     }
3025
3026     int c = m_cursor; // cursor position after insertion of commit string
3027     if (event->replacementStart() <= 0)
3028         c += event->commitString().length() - qMin(-event->replacementStart(), event->replacementLength());
3029
3030     m_cursor += event->replacementStart();
3031     if (m_cursor < 0)
3032         m_cursor = 0;
3033
3034     // insert commit string
3035     if (event->replacementLength()) {
3036         m_selstart = m_cursor;
3037         m_selend = m_selstart + event->replacementLength();
3038         m_selend = qMin(m_selend, m_text.length());
3039         removeSelectedText();
3040     }
3041     if (!event->commitString().isEmpty()) {
3042         internalInsert(event->commitString());
3043         cursorPositionChanged = true;
3044     }
3045
3046     m_cursor = qBound(0, c, m_text.length());
3047
3048     for (int i = 0; i < event->attributes().size(); ++i) {
3049         const QInputMethodEvent::Attribute &a = event->attributes().at(i);
3050         if (a.type == QInputMethodEvent::Selection) {
3051             m_cursor = qBound(0, a.start + a.length, m_text.length());
3052             if (a.length) {
3053                 m_selstart = qMax(0, qMin(a.start, m_text.length()));
3054                 m_selend = m_cursor;
3055                 if (m_selend < m_selstart) {
3056                     qSwap(m_selstart, m_selend);
3057                 }
3058                 selectionChange = true;
3059             } else {
3060                 m_selstart = m_selend = 0;
3061             }
3062             cursorPositionChanged = true;
3063         }
3064     }
3065 #ifndef QT_NO_IM
3066     m_textLayout.setPreeditArea(m_cursor, event->preeditString());
3067 #endif //QT_NO_IM
3068     const int oldPreeditCursor = m_preeditCursor;
3069     m_preeditCursor = event->preeditString().length();
3070     m_hideCursor = false;
3071     QList<QTextLayout::FormatRange> formats;
3072     for (int i = 0; i < event->attributes().size(); ++i) {
3073         const QInputMethodEvent::Attribute &a = event->attributes().at(i);
3074         if (a.type == QInputMethodEvent::Cursor) {
3075             m_preeditCursor = a.start;
3076             m_hideCursor = !a.length;
3077         } else if (a.type == QInputMethodEvent::TextFormat) {
3078             QTextCharFormat f = qvariant_cast<QTextFormat>(a.value).toCharFormat();
3079             if (f.isValid()) {
3080                 QTextLayout::FormatRange o;
3081                 o.start = a.start + m_cursor;
3082                 o.length = a.length;
3083                 o.format = f;
3084                 formats.append(o);
3085             }
3086         }
3087     }
3088     m_textLayout.setAdditionalFormats(formats);
3089
3090     updateDisplayText(/*force*/ true);
3091     if (cursorPositionChanged) {
3092         emitCursorPositionChanged();
3093     } else if (m_preeditCursor != oldPreeditCursor) {
3094         q->updateCursorRectangle();
3095     }
3096
3097     bool tentativeCommitChanged = m_tentativeCommit != event->tentativeCommitString();
3098
3099     if (tentativeCommitChanged) {
3100         m_textDirty = true;
3101         m_tentativeCommit = event->tentativeCommitString();
3102     }
3103
3104     if (isGettingInput || tentativeCommitChanged)
3105         finishChange(priorState);
3106
3107     if (selectionChange) {
3108         emit q->selectionChanged();
3109         q->updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorPosition
3110                             | Qt::ImCursorPosition | Qt::ImCurrentSelection);
3111     }
3112 }
3113
3114 /*!
3115     \internal
3116
3117     Sets the selection to cover the word at the given cursor position.
3118     The word boundaries are defined by the behavior of QTextLayout::SkipWords
3119     cursor mode.
3120 */
3121 void QQuickTextInputPrivate::selectWordAtPos(int cursor)
3122 {
3123     int next = cursor + 1;
3124     if (next > end())
3125         --next;
3126     int c = m_textLayout.previousCursorPosition(next, QTextLayout::SkipWords);
3127     moveCursor(c, false);
3128     // ## text layout should support end of words.
3129     int end = m_textLayout.nextCursorPosition(c, QTextLayout::SkipWords);
3130     while (end > cursor && m_text[end-1].isSpace())
3131         --end;
3132     moveCursor(end, true);
3133 }
3134
3135 /*!
3136     \internal
3137
3138     Completes a change to the line control text.  If the change is not valid
3139     will undo the line control state back to the given \a validateFromState.
3140
3141     If \a edited is true and the change is valid, will emit textEdited() in
3142     addition to textChanged().  Otherwise only emits textChanged() on a valid
3143     change.
3144
3145     The \a update value is currently unused.
3146 */
3147 bool QQuickTextInputPrivate::finishChange(int validateFromState, bool update, bool /*edited*/)
3148 {
3149     Q_Q(QQuickTextInput);
3150
3151     Q_UNUSED(update)
3152     bool inputMethodAttributesChanged = m_textDirty || m_selDirty;
3153     bool alignmentChanged = false;
3154
3155     if (m_textDirty) {
3156         // do validation
3157         bool wasValidInput = m_validInput;
3158         bool wasAcceptable = m_acceptableInput;
3159         m_validInput = true;
3160         m_acceptableInput = true;
3161 #ifndef QT_NO_VALIDATOR
3162         if (m_validator) {
3163             QString textCopy = m_text;
3164             int cursorCopy = m_cursor;
3165             QValidator::State state = m_validator->validate(textCopy, cursorCopy);
3166             m_validInput = state != QValidator::Invalid;
3167             m_acceptableInput = state == QValidator::Acceptable;
3168             if (m_validInput) {
3169                 if (m_text != textCopy) {
3170                     internalSetText(textCopy, cursorCopy);
3171                     return true;
3172                 }
3173                 m_cursor = cursorCopy;
3174
3175                 if (!m_tentativeCommit.isEmpty()) {
3176                     textCopy.insert(m_cursor, m_tentativeCommit);
3177                     bool validInput = m_validator->validate(textCopy, cursorCopy) != QValidator::Invalid;
3178                     if (!validInput)
3179                         m_tentativeCommit.clear();
3180                 }
3181             } else {
3182                 m_tentativeCommit.clear();
3183             }
3184         }
3185 #endif
3186         if (validateFromState >= 0 && wasValidInput && !m_validInput) {
3187             if (m_transactions.count())
3188                 return false;
3189             internalUndo(validateFromState);
3190             m_history.resize(m_undoState);
3191             if (m_modifiedState > m_undoState)
3192                 m_modifiedState = -1;
3193             m_validInput = true;
3194             m_acceptableInput = wasAcceptable;
3195             m_textDirty = false;
3196         }
3197
3198         if (m_textDirty) {
3199             m_textDirty = false;
3200             m_preeditDirty = false;
3201             alignmentChanged = determineHorizontalAlignment();
3202             emit q->textChanged();
3203         }
3204
3205         updateDisplayText(alignmentChanged);
3206
3207         if (m_acceptableInput != wasAcceptable)
3208             emit q->acceptableInputChanged();
3209     }
3210     if (m_preeditDirty) {
3211         m_preeditDirty = false;
3212         if (determineHorizontalAlignment()) {
3213             alignmentChanged = true;
3214             updateLayout();
3215         }
3216     }
3217
3218     if (m_selDirty) {
3219         m_selDirty = false;
3220         emit q->selectionChanged();
3221     }
3222
3223     inputMethodAttributesChanged |= (m_cursor == m_lastCursorPos);
3224     if (inputMethodAttributesChanged)
3225         q->updateInputMethod();
3226     emitUndoRedoChanged();
3227
3228     if (!emitCursorPositionChanged() && alignmentChanged)
3229         q->updateCursorRectangle();
3230
3231     return true;
3232 }
3233
3234 /*!
3235     \internal
3236
3237     An internal function for setting the text of the line control.
3238 */
3239 void QQuickTextInputPrivate::internalSetText(const QString &txt, int pos, bool edited)
3240 {
3241     Q_Q(QQuickTextInput);
3242     internalDeselect();
3243     QString oldText = m_text;
3244     if (m_maskData) {
3245         m_text = maskString(0, txt, true);
3246         m_text += clearString(m_text.length(), m_maxLength - m_text.length());
3247     } else {
3248         m_text = txt.isEmpty() ? txt : txt.left(m_maxLength);
3249     }
3250     m_history.clear();
3251     m_modifiedState =  m_undoState = 0;
3252     m_cursor = (pos < 0 || pos > m_text.length()) ? m_text.length() : pos;
3253     m_textDirty = (oldText != m_text);
3254
3255     bool changed = finishChange(-1, true, edited);
3256 #ifdef QT_NO_ACCESSIBILITY
3257     Q_UNUSED(changed)
3258 #else
3259     if (changed)
3260         QAccessible::updateAccessibility(QAccessibleEvent(QAccessible::TextUpdated, q, 0));
3261 #endif
3262 }
3263
3264
3265 /*!
3266     \internal
3267
3268     Adds the given \a command to the undo history
3269     of the line control.  Does not apply the command.
3270 */
3271 void QQuickTextInputPrivate::addCommand(const Command &cmd)
3272 {
3273     if (m_separator && m_undoState && m_history[m_undoState - 1].type != Separator) {
3274         m_history.resize(m_undoState + 2);
3275         m_history[m_undoState++] = Command(Separator, m_cursor, 0, m_selstart, m_selend);
3276     } else {
3277         m_history.resize(m_undoState + 1);
3278     }
3279     m_separator = false;
3280     m_history[m_undoState++] = cmd;
3281 }
3282
3283 /*!
3284     \internal
3285
3286     Inserts the given string \a s into the line
3287     control.
3288
3289     Also adds the appropriate commands into the undo history.
3290     This function does not call finishChange(), and may leave the text
3291     in an invalid state.
3292 */
3293 void QQuickTextInputPrivate::internalInsert(const QString &s)
3294 {
3295 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
3296     Q_Q(QQuickTextInput);
3297     if (m_echoMode == QQuickTextInput::Password)
3298         m_passwordEchoTimer.start(qt_passwordEchoDelay, q);
3299 #endif
3300     if (hasSelectedText())
3301         addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3302     if (m_maskData) {
3303         QString ms = maskString(m_cursor, s);
3304         for (int i = 0; i < (int) ms.length(); ++i) {
3305             addCommand (Command(DeleteSelection, m_cursor + i, m_text.at(m_cursor + i), -1, -1));
3306             addCommand(Command(Insert, m_cursor + i, ms.at(i), -1, -1));
3307         }
3308         m_text.replace(m_cursor, ms.length(), ms);
3309         m_cursor += ms.length();
3310         m_cursor = nextMaskBlank(m_cursor);
3311         m_textDirty = true;
3312     } else {
3313         int remaining = m_maxLength - m_text.length();
3314         if (remaining != 0) {
3315             m_text.insert(m_cursor, s.left(remaining));
3316             for (int i = 0; i < (int) s.left(remaining).length(); ++i)
3317                addCommand(Command(Insert, m_cursor++, s.at(i), -1, -1));
3318             m_textDirty = true;
3319         }
3320     }
3321 }
3322
3323 /*!
3324     \internal
3325
3326     deletes a single character from the current text.  If \a wasBackspace,
3327     the character prior to the cursor is removed.  Otherwise the character
3328     after the cursor is removed.
3329
3330     Also adds the appropriate commands into the undo history.
3331     This function does not call finishChange(), and may leave the text
3332     in an invalid state.
3333 */
3334 void QQuickTextInputPrivate::internalDelete(bool wasBackspace)
3335 {
3336     if (m_cursor < (int) m_text.length()) {
3337         cancelPasswordEchoTimer();
3338         if (hasSelectedText())
3339             addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3340         addCommand(Command((CommandType)((m_maskData ? 2 : 0) + (wasBackspace ? Remove : Delete)),
3341                    m_cursor, m_text.at(m_cursor), -1, -1));
3342         if (m_maskData) {
3343             m_text.replace(m_cursor, 1, clearString(m_cursor, 1));
3344             addCommand(Command(Insert, m_cursor, m_text.at(m_cursor), -1, -1));
3345         } else {
3346             m_text.remove(m_cursor, 1);
3347         }
3348         m_textDirty = true;
3349     }
3350 }
3351
3352 /*!
3353     \internal
3354
3355     removes the currently selected text from the line control.
3356
3357     Also adds the appropriate commands into the undo history.
3358     This function does not call finishChange(), and may leave the text
3359     in an invalid state.
3360 */
3361 void QQuickTextInputPrivate::removeSelectedText()
3362 {
3363     if (m_selstart < m_selend && m_selend <= (int) m_text.length()) {
3364         cancelPasswordEchoTimer();
3365         separate();
3366         int i ;
3367         addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3368         if (m_selstart <= m_cursor && m_cursor < m_selend) {
3369             // cursor is within the selection. Split up the commands
3370             // to be able to restore the correct cursor position
3371             for (i = m_cursor; i >= m_selstart; --i)
3372                 addCommand (Command(DeleteSelection, i, m_text.at(i), -1, 1));
3373             for (i = m_selend - 1; i > m_cursor; --i)
3374                 addCommand (Command(DeleteSelection, i - m_cursor + m_selstart - 1, m_text.at(i), -1, -1));
3375         } else {
3376             for (i = m_selend-1; i >= m_selstart; --i)
3377                 addCommand (Command(RemoveSelection, i, m_text.at(i), -1, -1));
3378         }
3379         if (m_maskData) {
3380             m_text.replace(m_selstart, m_selend - m_selstart,  clearString(m_selstart, m_selend - m_selstart));
3381             for (int i = 0; i < m_selend - m_selstart; ++i)
3382                 addCommand(Command(Insert, m_selstart + i, m_text.at(m_selstart + i), -1, -1));
3383         } else {
3384             m_text.remove(m_selstart, m_selend - m_selstart);
3385         }
3386         if (m_cursor > m_selstart)
3387             m_cursor -= qMin(m_cursor, m_selend) - m_selstart;
3388         internalDeselect();
3389         m_textDirty = true;
3390     }
3391 }
3392
3393 /*!
3394     \internal
3395
3396     Parses the input mask specified by \a maskFields to generate
3397     the mask data used to handle input masks.
3398 */
3399 void QQuickTextInputPrivate::parseInputMask(const QString &maskFields)
3400 {
3401     int delimiter = maskFields.indexOf(QLatin1Char(';'));
3402     if (maskFields.isEmpty() || delimiter == 0) {
3403         if (m_maskData) {
3404             delete [] m_maskData;
3405             m_maskData = 0;
3406             m_maxLength = 32767;
3407             internalSetText(QString());
3408         }
3409         return;
3410     }
3411
3412     if (delimiter == -1) {
3413         m_blank = QLatin1Char(' ');
3414         m_inputMask = maskFields;
3415     } else {
3416         m_inputMask = maskFields.left(delimiter);
3417         m_blank = (delimiter + 1 < maskFields.length()) ? maskFields[delimiter + 1] : QLatin1Char(' ');
3418     }
3419
3420     // calculate m_maxLength / m_maskData length
3421     m_maxLength = 0;
3422     QChar c = 0;
3423     for (int i=0; i<m_inputMask.length(); i++) {
3424         c = m_inputMask.at(i);
3425         if (i > 0 && m_inputMask.at(i-1) == QLatin1Char('\\')) {
3426             m_maxLength++;
3427             continue;
3428         }
3429         if (c != QLatin1Char('\\') && c != QLatin1Char('!') &&
3430              c != QLatin1Char('<') && c != QLatin1Char('>') &&
3431              c != QLatin1Char('{') && c != QLatin1Char('}') &&
3432              c != QLatin1Char('[') && c != QLatin1Char(']'))
3433             m_maxLength++;
3434     }
3435
3436     delete [] m_maskData;
3437     m_maskData = new MaskInputData[m_maxLength];
3438
3439     MaskInputData::Casemode m = MaskInputData::NoCaseMode;
3440     c = 0;
3441     bool s;
3442     bool escape = false;
3443     int index = 0;
3444     for (int i = 0; i < m_inputMask.length(); i++) {
3445         c = m_inputMask.at(i);
3446         if (escape) {
3447             s = true;
3448             m_maskData[index].maskChar = c;
3449             m_maskData[index].separator = s;
3450             m_maskData[index].caseMode = m;
3451             index++;
3452             escape = false;
3453         } else if (c == QLatin1Char('<')) {
3454                 m = MaskInputData::Lower;
3455         } else if (c == QLatin1Char('>')) {
3456             m = MaskInputData::Upper;
3457         } else if (c == QLatin1Char('!')) {
3458             m = MaskInputData::NoCaseMode;
3459         } else if (c != QLatin1Char('{') && c != QLatin1Char('}') && c != QLatin1Char('[') && c != QLatin1Char(']')) {
3460             switch (c.unicode()) {
3461             case 'A':
3462             case 'a':
3463             case 'N':
3464             case 'n':
3465             case 'X':
3466             case 'x':
3467             case '9':
3468             case '0':
3469             case 'D':
3470             case 'd':
3471             case '#':
3472             case 'H':
3473             case 'h':
3474             case 'B':
3475             case 'b':
3476                 s = false;
3477                 break;
3478             case '\\':
3479                 escape = true;
3480             default:
3481                 s = true;
3482                 break;
3483             }
3484
3485             if (!escape) {
3486                 m_maskData[index].maskChar = c;
3487                 m_maskData[index].separator = s;
3488                 m_maskData[index].caseMode = m;
3489                 index++;
3490             }
3491         }
3492     }
3493     internalSetText(m_text);
3494 }
3495
3496
3497 /*!
3498     \internal
3499
3500     checks if the key is valid compared to the inputMask
3501 */
3502 bool QQuickTextInputPrivate::isValidInput(QChar key, QChar mask) const
3503 {
3504     switch (mask.unicode()) {
3505     case 'A':
3506         if (key.isLetter())
3507             return true;
3508         break;
3509     case 'a':
3510         if (key.isLetter() || key == m_blank)
3511             return true;
3512         break;
3513     case 'N':
3514         if (key.isLetterOrNumber())
3515             return true;
3516         break;
3517     case 'n':
3518         if (key.isLetterOrNumber() || key == m_blank)
3519             return true;
3520         break;
3521     case 'X':
3522         if (key.isPrint())
3523             return true;
3524         break;
3525     case 'x':
3526         if (key.isPrint() || key == m_blank)
3527             return true;
3528         break;
3529     case '9':
3530         if (key.isNumber())
3531             return true;
3532         break;
3533     case '0':
3534         if (key.isNumber() || key == m_blank)
3535             return true;
3536         break;
3537     case 'D':
3538         if (key.isNumber() && key.digitValue() > 0)
3539             return true;
3540         break;
3541     case 'd':
3542         if ((key.isNumber() && key.digitValue() > 0) || key == m_blank)
3543             return true;
3544         break;
3545     case '#':
3546         if (key.isNumber() || key == QLatin1Char('+') || key == QLatin1Char('-') || key == m_blank)
3547             return true;
3548         break;
3549     case 'B':
3550         if (key == QLatin1Char('0') || key == QLatin1Char('1'))
3551             return true;
3552         break;
3553     case 'b':
3554         if (key == QLatin1Char('0') || key == QLatin1Char('1') || key == m_blank)
3555             return true;
3556         break;
3557     case 'H':
3558         if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')))
3559             return true;
3560         break;
3561     case 'h':
3562         if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')) || key == m_blank)
3563             return true;
3564         break;
3565     default:
3566         break;
3567     }
3568     return false;
3569 }
3570
3571 /*!
3572     \internal
3573
3574     Returns true if the given text \a str is valid for any
3575     validator or input mask set for the line control.
3576
3577     Otherwise returns false
3578 */
3579 QQuickTextInputPrivate::ValidatorState QQuickTextInputPrivate::hasAcceptableInput(const QString &str) const
3580 {
3581 #ifndef QT_NO_VALIDATOR
3582     QString textCopy = str;
3583     int cursorCopy = m_cursor;
3584     if (m_validator) {
3585         QValidator::State state = m_validator->validate(textCopy, cursorCopy);
3586         if (state != QValidator::Acceptable)
3587             return ValidatorState(state);
3588     }
3589 #endif
3590
3591     if (!m_maskData)
3592         return AcceptableInput;
3593
3594     if (str.length() != m_maxLength)
3595         return InvalidInput;
3596
3597     for (int i=0; i < m_maxLength; ++i) {
3598         if (m_maskData[i].separator) {
3599             if (str.at(i) != m_maskData[i].maskChar)
3600                 return InvalidInput;
3601         } else {
3602             if (!isValidInput(str.at(i), m_maskData[i].maskChar))
3603                 return InvalidInput;
3604         }
3605     }
3606     return AcceptableInput;
3607 }
3608
3609 /*!
3610     \internal
3611
3612     Applies the inputMask on \a str starting from position \a pos in the mask. \a clear
3613     specifies from where characters should be gotten when a separator is met in \a str - true means
3614     that blanks will be used, false that previous input is used.
3615     Calling this when no inputMask is set is undefined.
3616 */
3617 QString QQuickTextInputPrivate::maskString(uint pos, const QString &str, bool clear) const
3618 {
3619     if (pos >= (uint)m_maxLength)
3620         return QString::fromLatin1("");
3621
3622     QString fill;
3623     fill = clear ? clearString(0, m_maxLength) : m_text;
3624
3625     int strIndex = 0;
3626     QString s = QString::fromLatin1("");
3627     int i = pos;
3628     while (i < m_maxLength) {
3629         if (strIndex < str.length()) {
3630             if (m_maskData[i].separator) {
3631                 s += m_maskData[i].maskChar;
3632                 if (str[(int)strIndex] == m_maskData[i].maskChar)
3633                     strIndex++;
3634                 ++i;
3635             } else {
3636                 if (isValidInput(str[(int)strIndex], m_maskData[i].maskChar)) {
3637                     switch (m_maskData[i].caseMode) {
3638                     case MaskInputData::Upper:
3639                         s += str[(int)strIndex].toUpper();
3640                         break;
3641                     case MaskInputData::Lower:
3642                         s += str[(int)strIndex].toLower();
3643                         break;
3644                     default:
3645                         s += str[(int)strIndex];
3646                     }
3647                     ++i;
3648                 } else {
3649                     // search for separator first
3650                     int n = findInMask(i, true, true, str[(int)strIndex]);
3651                     if (n != -1) {
3652                         if (str.length() != 1 || i == 0 || (i > 0 && (!m_maskData[i-1].separator || m_maskData[i-1].maskChar != str[(int)strIndex]))) {
3653                             s += fill.mid(i, n-i+1);
3654                             i = n + 1; // update i to find + 1
3655                         }
3656                     } else {
3657                         // search for valid m_blank if not
3658                         n = findInMask(i, true, false, str[(int)strIndex]);
3659                         if (n != -1) {
3660                             s += fill.mid(i, n-i);
3661                             switch (m_maskData[n].caseMode) {
3662                             case MaskInputData::Upper:
3663                                 s += str[(int)strIndex].toUpper();
3664                                 break;
3665                             case MaskInputData::Lower:
3666                                 s += str[(int)strIndex].toLower();
3667                                 break;
3668                             default:
3669                                 s += str[(int)strIndex];
3670                             }
3671                             i = n + 1; // updates i to find + 1
3672                         }
3673                     }
3674                 }
3675                 ++strIndex;
3676             }
3677         } else
3678             break;
3679     }
3680
3681     return s;
3682 }
3683
3684
3685
3686 /*!
3687     \internal
3688
3689     Returns a "cleared" string with only separators and blank chars.
3690     Calling this when no inputMask is set is undefined.
3691 */
3692 QString QQuickTextInputPrivate::clearString(uint pos, uint len) const
3693 {
3694     if (pos >= (uint)m_maxLength)
3695         return QString();
3696
3697     QString s;
3698     int end = qMin((uint)m_maxLength, pos + len);
3699     for (int i = pos; i < end; ++i)
3700         if (m_maskData[i].separator)
3701             s += m_maskData[i].maskChar;
3702         else
3703             s += m_blank;
3704
3705     return s;
3706 }
3707
3708 /*!
3709     \internal
3710
3711     Strips blank parts of the input in a QQuickTextInputPrivate when an inputMask is set,
3712     separators are still included. Typically "127.0__.0__.1__" becomes "127.0.0.1".
3713 */
3714 QString QQuickTextInputPrivate::stripString(const QString &str) const
3715 {
3716     if (!m_maskData)
3717         return str;
3718
3719     QString s;
3720     int end = qMin(m_maxLength, (int)str.length());
3721     for (int i = 0; i < end; ++i) {
3722         if (m_maskData[i].separator)
3723             s += m_maskData[i].maskChar;
3724         else if (str[i] != m_blank)
3725             s += str[i];
3726     }
3727
3728     return s;
3729 }
3730
3731 /*!
3732     \internal
3733     searches forward/backward in m_maskData for either a separator or a m_blank
3734 */
3735 int QQuickTextInputPrivate::findInMask(int pos, bool forward, bool findSeparator, QChar searchChar) const
3736 {
3737     if (pos >= m_maxLength || pos < 0)
3738         return -1;
3739
3740     int end = forward ? m_maxLength : -1;
3741     int step = forward ? 1 : -1;
3742     int i = pos;
3743
3744     while (i != end) {
3745         if (findSeparator) {
3746             if (m_maskData[i].separator && m_maskData[i].maskChar == searchChar)
3747                 return i;
3748         } else {
3749             if (!m_maskData[i].separator) {
3750                 if (searchChar.isNull())
3751                     return i;
3752                 else if (isValidInput(searchChar, m_maskData[i].maskChar))
3753                     return i;
3754             }
3755         }
3756         i += step;
3757     }
3758     return -1;
3759 }
3760
3761 void QQuickTextInputPrivate::internalUndo(int until)
3762 {
3763     if (!isUndoAvailable())
3764         return;
3765     cancelPasswordEchoTimer();
3766     internalDeselect();
3767     while (m_undoState && m_undoState > until) {
3768         Command& cmd = m_history[--m_undoState];
3769         switch (cmd.type) {
3770         case Insert:
3771             m_text.remove(cmd.pos, 1);
3772             m_cursor = cmd.pos;
3773             break;
3774         case SetSelection:
3775             m_selstart = cmd.selStart;
3776             m_selend = cmd.selEnd;
3777             m_cursor = cmd.pos;
3778             break;
3779         case Remove:
3780         case RemoveSelection:
3781             m_text.insert(cmd.pos, cmd.uc);
3782             m_cursor = cmd.pos + 1;
3783             break;
3784         case Delete:
3785         case DeleteSelection:
3786             m_text.insert(cmd.pos, cmd.uc);
3787             m_cursor = cmd.pos;
3788             break;
3789         case Separator:
3790             continue;
3791         }
3792         if (until < 0 && m_undoState) {
3793             Command& next = m_history[m_undoState-1];
3794             if (next.type != cmd.type && next.type < RemoveSelection
3795                  && (cmd.type < RemoveSelection || next.type == Separator))
3796                 break;
3797         }
3798     }
3799     m_textDirty = true;
3800 }
3801
3802 void QQuickTextInputPrivate::internalRedo()
3803 {
3804     if (!isRedoAvailable())
3805         return;
3806     internalDeselect();
3807     while (m_undoState < (int)m_history.size()) {
3808         Command& cmd = m_history[m_undoState++];
3809         switch (cmd.type) {
3810         case Insert:
3811             m_text.insert(cmd.pos, cmd.uc);
3812             m_cursor = cmd.pos + 1;
3813             break;
3814         case SetSelection:
3815             m_selstart = cmd.selStart;
3816             m_selend = cmd.selEnd;
3817             m_cursor = cmd.pos;
3818             break;
3819         case Remove:
3820         case Delete:
3821         case RemoveSelection:
3822         case DeleteSelection:
3823             m_text.remove(cmd.pos, 1);
3824             m_selstart = cmd.selStart;
3825             m_selend = cmd.selEnd;
3826             m_cursor = cmd.pos;
3827             break;
3828         case Separator:
3829             m_selstart = cmd.selStart;
3830             m_selend = cmd.selEnd;
3831             m_cursor = cmd.pos;
3832             break;
3833         }
3834         if (m_undoState < (int)m_history.size()) {
3835             Command& next = m_history[m_undoState];
3836             if (next.type != cmd.type && cmd.type < RemoveSelection && next.type != Separator
3837                  && (next.type < RemoveSelection || cmd.type == Separator))
3838                 break;
3839         }
3840     }
3841     m_textDirty = true;
3842 }
3843
3844 void QQuickTextInputPrivate::emitUndoRedoChanged()
3845 {
3846     Q_Q(QQuickTextInput);
3847     const bool previousUndo = canUndo;
3848     const bool previousRedo = canRedo;
3849
3850     canUndo = isUndoAvailable();
3851     canRedo = isRedoAvailable();
3852
3853     if (previousUndo != canUndo)
3854         emit q->canUndoChanged();
3855     if (previousRedo != canRedo)
3856         emit q->canRedoChanged();
3857 }
3858
3859 /*!
3860     \internal
3861
3862     If the current cursor position differs from the last emitted cursor
3863     position, emits cursorPositionChanged().
3864 */
3865 bool QQuickTextInputPrivate::emitCursorPositionChanged()
3866 {
3867     Q_Q(QQuickTextInput);
3868     if (m_cursor != m_lastCursorPos) {
3869         m_lastCursorPos = m_cursor;
3870
3871         q->updateCursorRectangle();
3872         emit q->cursorPositionChanged();
3873         // XXX todo - not in 4.8?
3874     #if 0
3875         resetCursorBlinkTimer();
3876     #endif
3877
3878         if (!hasSelectedText()) {
3879             if (lastSelectionStart != m_cursor) {
3880                 lastSelectionStart = m_cursor;
3881                 emit q->selectionStartChanged();
3882             }
3883             if (lastSelectionEnd != m_cursor) {
3884                 lastSelectionEnd = m_cursor;
3885                 emit q->selectionEndChanged();
3886             }
3887         }
3888
3889 #ifndef QT_NO_ACCESSIBILITY
3890         QAccessible::updateAccessibility(QAccessibleEvent(QAccessible::TextCaretMoved, q, 0));
3891 #endif
3892
3893         return true;
3894     }
3895     return false;
3896 }
3897
3898
3899 void QQuickTextInputPrivate::setCursorBlinkPeriod(int msec)
3900 {
3901     Q_Q(QQuickTextInput);
3902     if (msec == m_blinkPeriod)
3903         return;
3904     if (m_blinkTimer) {
3905         q->killTimer(m_blinkTimer);
3906     }
3907     if (msec) {
3908         m_blinkTimer = q->startTimer(msec / 2);
3909         m_blinkStatus = 1;
3910     } else {
3911         m_blinkTimer = 0;
3912         if (m_blinkStatus == 1) {
3913             updateType = UpdatePaintNode;
3914             q->update();
3915         }
3916     }
3917     m_blinkPeriod = msec;
3918 }
3919
3920 void QQuickTextInputPrivate::resetCursorBlinkTimer()
3921 {
3922     Q_Q(QQuickTextInput);
3923     if (m_blinkPeriod == 0 || m_blinkTimer == 0)
3924         return;
3925     q->killTimer(m_blinkTimer);
3926     m_blinkTimer = q->startTimer(m_blinkPeriod / 2);
3927     m_blinkStatus = 1;
3928 }
3929
3930 void QQuickTextInput::timerEvent(QTimerEvent *event)
3931 {
3932     Q_D(QQuickTextInput);
3933     if (event->timerId() == d->m_blinkTimer) {
3934         d->m_blinkStatus = !d->m_blinkStatus;
3935         d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
3936         update();
3937     } else if (event->timerId() == d->m_deleteAllTimer) {
3938         killTimer(d->m_deleteAllTimer);
3939         d->m_deleteAllTimer = 0;
3940         d->clear();
3941 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
3942     } else if (event->timerId() == d->m_passwordEchoTimer.timerId()) {
3943         d->m_passwordEchoTimer.stop();
3944         d->updateDisplayText();
3945 #endif
3946     }
3947 }
3948
3949 void QQuickTextInputPrivate::processKeyEvent(QKeyEvent* event)
3950 {
3951     Q_Q(QQuickTextInput);
3952     bool inlineCompletionAccepted = false;
3953
3954     if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) {
3955         if (hasAcceptableInput(m_text) || fixup()) {
3956             emit q->accepted();
3957         }
3958         if (inlineCompletionAccepted)
3959             event->accept();
3960         else
3961             event->ignore();
3962         return;
3963     }
3964
3965     if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit
3966         && !m_passwordEchoEditing
3967         && !m_readOnly
3968         && !event->text().isEmpty()
3969         && !(event->modifiers() & Qt::ControlModifier)) {
3970         // Clear the edit and reset to normal echo mode while editing; the
3971         // echo mode switches back when the edit loses focus
3972         // ### resets current content.  dubious code; you can
3973         // navigate with keys up, down, back, and select(?), but if you press
3974         // "left" or "right" it clears?
3975         updatePasswordEchoEditing(true);
3976         clear();
3977     }
3978
3979     bool unknown = false;
3980     bool visual = cursorMoveStyle() == Qt::VisualMoveStyle;
3981
3982     if (false) {
3983     }
3984 #ifndef QT_NO_SHORTCUT
3985     else if (event == QKeySequence::Undo) {
3986         if (!m_readOnly)
3987             q->undo();
3988     }
3989     else if (event == QKeySequence::Redo) {
3990         if (!m_readOnly)
3991             q->redo();
3992     }
3993     else if (event == QKeySequence::SelectAll) {
3994         selectAll();
3995     }
3996 #ifndef QT_NO_CLIPBOARD
3997     else if (event == QKeySequence::Copy) {
3998         copy();
3999     }
4000     else if (event == QKeySequence::Paste) {
4001         if (!m_readOnly) {
4002             QClipboard::Mode mode = QClipboard::Clipboard;
4003             paste(mode);
4004         }
4005     }
4006     else if (event == QKeySequence::Cut) {
4007         if (!m_readOnly) {
4008             copy();
4009             del();
4010         }
4011     }
4012     else if (event == QKeySequence::DeleteEndOfLine) {
4013         if (!m_readOnly) {
4014             setSelection(m_cursor, end());
4015             copy();
4016             del();
4017         }
4018     }
4019 #endif //QT_NO_CLIPBOARD
4020     else if (event == QKeySequence::MoveToStartOfLine || event == QKeySequence::MoveToStartOfBlock) {
4021         home(0);
4022     }
4023     else if (event == QKeySequence::MoveToEndOfLine || event == QKeySequence::MoveToEndOfBlock) {
4024         end(0);
4025     }
4026     else if (event == QKeySequence::SelectStartOfLine || event == QKeySequence::SelectStartOfBlock) {
4027         home(1);
4028     }
4029     else if (event == QKeySequence::SelectEndOfLine || event == QKeySequence::SelectEndOfBlock) {
4030         end(1);
4031     }
4032     else if (event == QKeySequence::MoveToNextChar) {
4033         if (hasSelectedText()) {
4034             moveCursor(selectionEnd(), false);
4035         } else {
4036             cursorForward(0, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
4037         }
4038     }
4039     else if (event == QKeySequence::SelectNextChar) {
4040         cursorForward(1, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
4041     }
4042     else if (event == QKeySequence::MoveToPreviousChar) {
4043         if (hasSelectedText()) {
4044             moveCursor(selectionStart(), false);
4045         } else {
4046             cursorForward(0, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
4047         }
4048     }
4049     else if (event == QKeySequence::SelectPreviousChar) {
4050         cursorForward(1, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
4051     }
4052     else if (event == QKeySequence::MoveToNextWord) {
4053         if (m_echoMode == QQuickTextInput::Normal)
4054             layoutDirection() == Qt::LeftToRight ? cursorWordForward(0) : cursorWordBackward(0);
4055         else
4056             layoutDirection() == Qt::LeftToRight ? end(0) : home(0);
4057     }
4058     else if (event == QKeySequence::MoveToPreviousWord) {
4059         if (m_echoMode == QQuickTextInput::Normal)
4060             layoutDirection() == Qt::LeftToRight ? cursorWordBackward(0) : cursorWordForward(0);
4061         else if (!m_readOnly) {
4062             layoutDirection() == Qt::LeftToRight ? home(0) : end(0);
4063         }
4064     }
4065     else if (event == QKeySequence::SelectNextWord) {
4066         if (m_echoMode == QQuickTextInput::Normal)
4067             layoutDirection() == Qt::LeftToRight ? cursorWordForward(1) : cursorWordBackward(1);
4068         else
4069             layoutDirection() == Qt::LeftToRight ? end(1) : home(1);
4070     }
4071     else if (event == QKeySequence::SelectPreviousWord) {
4072         if (m_echoMode == QQuickTextInput::Normal)
4073             layoutDirection() == Qt::LeftToRight ? cursorWordBackward(1) : cursorWordForward(1);
4074         else
4075             layoutDirection() == Qt::LeftToRight ? home(1) : end(1);
4076     }
4077     else if (event == QKeySequence::Delete) {
4078         if (!m_readOnly)
4079             del();
4080     }
4081     else if (event == QKeySequence::DeleteEndOfWord) {
4082         if (!m_readOnly) {
4083             cursorWordForward(true);
4084             del();
4085         }
4086     }
4087     else if (event == QKeySequence::DeleteStartOfWord) {
4088         if (!m_readOnly) {
4089             cursorWordBackward(true);
4090             del();
4091         }
4092     }
4093 #endif // QT_NO_SHORTCUT
4094     else {
4095         bool handled = false;
4096         if (event->modifiers() & Qt::ControlModifier) {
4097             switch (event->key()) {
4098             case Qt::Key_Backspace:
4099                 if (!m_readOnly) {
4100                     cursorWordBackward(true);
4101                     del();
4102                 }
4103                 break;
4104             default:
4105                 if (!handled)
4106                     unknown = true;
4107             }
4108         } else { // ### check for *no* modifier
4109             switch (event->key()) {
4110             case Qt::Key_Backspace:
4111                 if (!m_readOnly) {
4112                     backspace();
4113                 }
4114                 break;
4115             default:
4116                 if (!handled)
4117                     unknown = true;
4118             }
4119         }
4120     }
4121
4122     if (event->key() == Qt::Key_Direction_L || event->key() == Qt::Key_Direction_R) {
4123         setLayoutDirection((event->key() == Qt::Key_Direction_L) ? Qt::LeftToRight : Qt::RightToLeft);
4124         unknown = false;
4125     }
4126
4127     if (unknown && !m_readOnly) {
4128         QString t = event->text();
4129         if (!t.isEmpty() && t.at(0).isPrint()) {
4130             insert(t);
4131             event->accept();
4132             return;
4133         }
4134     }
4135
4136     if (unknown)
4137         event->ignore();
4138     else
4139         event->accept();
4140 }
4141
4142
4143 QT_END_NAMESPACE
4144