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