Adapt to QInputPanel::inputDirection() API
[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()) {
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         }
2320     }
2321     QQuickItem::itemChange(change, value);
2322 }
2323
2324 /*!
2325     \qmlproperty bool QtQuick2::TextInput::inputMethodComposing
2326
2327
2328     This property holds whether the TextInput has partial text input from an
2329     input method.
2330
2331     While it is composing an input method may rely on mouse or key events from
2332     the TextInput to edit or commit the partial text.  This property can be
2333     used to determine when to disable events handlers that may interfere with
2334     the correct operation of an input method.
2335 */
2336 bool QQuickTextInput::isInputMethodComposing() const
2337 {
2338     Q_D(const QQuickTextInput);
2339     return d->preeditAreaText().length() > 0;
2340 }
2341
2342 void QQuickTextInputPrivate::init()
2343 {
2344     Q_Q(QQuickTextInput);
2345     q->setSmooth(smooth);
2346     q->setAcceptedMouseButtons(Qt::LeftButton);
2347     q->setFlag(QQuickItem::ItemAcceptsInputMethod);
2348     q->setFlag(QQuickItem::ItemHasContents);
2349 #ifndef QT_NO_CLIPBOARD
2350     q->connect(QGuiApplication::clipboard(), SIGNAL(dataChanged()),
2351             q, SLOT(q_canPasteChanged()));
2352 #endif // QT_NO_CLIPBOARD
2353
2354     lastSelectionStart = 0;
2355     lastSelectionEnd = 0;
2356     selectedTextColor = m_palette.color(QPalette::HighlightedText);
2357     selectionColor = m_palette.color(QPalette::Highlight);
2358     determineHorizontalAlignment();
2359
2360     if (!qmlDisableDistanceField()) {
2361         QTextOption option = m_textLayout.textOption();
2362         option.setUseDesignMetrics(true);
2363         m_textLayout.setTextOption(option);
2364     }
2365 }
2366
2367 void QQuickTextInput::updateCursorRectangle()
2368 {
2369     Q_D(QQuickTextInput);
2370     if (!isComponentComplete())
2371         return;
2372
2373     d->updateHorizontalScroll();
2374     d->updateVerticalScroll();
2375     update();
2376     emit cursorRectangleChanged();
2377     if (d->cursorItem) {
2378         QRectF r = cursorRectangle();
2379         d->cursorItem->setPos(r.topLeft());
2380         d->cursorItem->setHeight(r.height());
2381     }
2382 }
2383
2384 void QQuickTextInput::selectionChanged()
2385 {
2386     Q_D(QQuickTextInput);
2387     d->textLayoutDirty = true; //TODO: Only update rect in selection
2388     update();
2389     emit selectedTextChanged();
2390
2391     if (d->lastSelectionStart != d->selectionStart()) {
2392         d->lastSelectionStart = d->selectionStart();
2393         if (d->lastSelectionStart == -1)
2394             d->lastSelectionStart = d->m_cursor;
2395         emit selectionStartChanged();
2396     }
2397     if (d->lastSelectionEnd != d->selectionEnd()) {
2398         d->lastSelectionEnd = d->selectionEnd();
2399         if (d->lastSelectionEnd == -1)
2400             d->lastSelectionEnd = d->m_cursor;
2401         emit selectionEndChanged();
2402     }
2403 }
2404
2405 void QQuickTextInputPrivate::showCursor()
2406 {
2407     if (textNode != 0 && textNode->cursorNode() != 0)
2408         textNode->cursorNode()->setColor(color);
2409 }
2410
2411 void QQuickTextInputPrivate::hideCursor()
2412 {
2413     if (textNode != 0 && textNode->cursorNode() != 0)
2414         textNode->cursorNode()->setColor(QColor(0, 0, 0, 0));
2415 }
2416
2417 QRectF QQuickTextInput::boundingRect() const
2418 {
2419     Q_D(const QQuickTextInput);
2420
2421     int cursorWidth = d->cursorItem ? d->cursorItem->width() : d->m_cursorWidth;
2422
2423     // Could include font max left/right bearings to either side of rectangle.
2424     QRectF r = QQuickImplicitSizeItem::boundingRect();
2425     r.setRight(r.right() + cursorWidth);
2426     return r;
2427 }
2428
2429 void QQuickTextInput::q_canPasteChanged()
2430 {
2431     Q_D(QQuickTextInput);
2432     bool old = d->canPaste;
2433 #ifndef QT_NO_CLIPBOARD
2434     if (const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData())
2435         d->canPaste = !d->m_readOnly && mimeData->hasText();
2436     else
2437         d->canPaste = false;
2438 #endif
2439
2440     bool changed = d->canPaste != old || !d->canPasteValid;
2441     d->canPasteValid = true;
2442     if (changed)
2443         emit canPasteChanged();
2444
2445 }
2446
2447 // ### these should come from QStyleHints
2448 const int textCursorWidth = 1;
2449 const bool fullWidthSelection = true;
2450
2451 /*!
2452     \internal
2453
2454     Updates the display text based of the current edit text
2455     If the text has changed will emit displayTextChanged()
2456 */
2457 void QQuickTextInputPrivate::updateDisplayText(bool forceUpdate)
2458 {
2459     QString orig = m_textLayout.text();
2460     QString str;
2461     if (m_echoMode == QQuickTextInput::NoEcho)
2462         str = QString::fromLatin1("");
2463     else
2464         str = m_text;
2465
2466     if (m_echoMode == QQuickTextInput::Password) {
2467          str.fill(m_passwordCharacter);
2468 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
2469         if (m_passwordEchoTimer.isActive() && m_cursor > 0 && m_cursor <= m_text.length()) {
2470             int cursor = m_cursor - 1;
2471             QChar uc = m_text.at(cursor);
2472             str[cursor] = uc;
2473             if (cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
2474                 // second half of a surrogate, check if we have the first half as well,
2475                 // if yes restore both at once
2476                 uc = m_text.at(cursor - 1);
2477                 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00)
2478                     str[cursor - 1] = uc;
2479             }
2480         }
2481 #endif
2482     } else if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
2483         str.fill(m_passwordCharacter);
2484     }
2485
2486     // replace certain non-printable characters with spaces (to avoid
2487     // drawing boxes when using fonts that don't have glyphs for such
2488     // characters)
2489     QChar* uc = str.data();
2490     for (int i = 0; i < (int)str.length(); ++i) {
2491         if ((uc[i] < 0x20 && uc[i] != 0x09)
2492             || uc[i] == QChar::LineSeparator
2493             || uc[i] == QChar::ParagraphSeparator
2494             || uc[i] == QChar::ObjectReplacementCharacter)
2495             uc[i] = QChar(0x0020);
2496     }
2497
2498     if (str != orig || forceUpdate) {
2499         m_textLayout.setText(str);
2500         updateLayout(); // polish?
2501         emit q_func()->displayTextChanged();
2502     }
2503 }
2504
2505 void QQuickTextInputPrivate::updateLayout()
2506 {
2507     Q_Q(QQuickTextInput);
2508
2509     if (!q->isComponentComplete())
2510         return;
2511
2512     QTextOption option = m_textLayout.textOption();
2513     option.setTextDirection(m_layoutDirection);
2514     option.setFlags(QTextOption::IncludeTrailingSpaces);
2515     option.setWrapMode(QTextOption::WrapMode(wrapMode));
2516     option.setAlignment(Qt::Alignment(q->effectiveHAlign()));
2517     m_textLayout.setTextOption(option);
2518     m_textLayout.setFont(font);
2519
2520     boundingRect = QRectF();
2521     m_textLayout.beginLayout();
2522     QTextLine line = m_textLayout.createLine();
2523     qreal lineWidth = q->widthValid() ? q->width() : INT_MAX;
2524     qreal height = 0;
2525     QTextLine firstLine = line;
2526     do {
2527         line.setLineWidth(lineWidth);
2528         line.setPosition(QPointF(line.position().x(), height));
2529         boundingRect = boundingRect.united(line.naturalTextRect());
2530
2531         height += line.height();
2532         line = m_textLayout.createLine();
2533     } while (line.isValid());
2534     m_textLayout.endLayout();
2535
2536     option.setWrapMode(QTextOption::NoWrap);
2537     m_textLayout.setTextOption(option);
2538
2539     m_ascent = qRound(firstLine.ascent());
2540     textLayoutDirty = true;
2541
2542     q->update();
2543     q->setImplicitSize(qCeil(boundingRect.width()), qCeil(boundingRect.height()));
2544
2545 }
2546
2547 #ifndef QT_NO_CLIPBOARD
2548 /*!
2549     \internal
2550
2551     Copies the currently selected text into the clipboard using the given
2552     \a mode.
2553
2554     \note If the echo mode is set to a mode other than Normal then copy
2555     will not work.  This is to prevent using copy as a method of bypassing
2556     password features of the line control.
2557 */
2558 void QQuickTextInputPrivate::copy(QClipboard::Mode mode) const
2559 {
2560     QString t = selectedText();
2561     if (!t.isEmpty() && m_echoMode == QQuickTextInput::Normal) {
2562         QGuiApplication::clipboard()->setText(t, mode);
2563     }
2564 }
2565
2566 /*!
2567     \internal
2568
2569     Inserts the text stored in the application clipboard into the line
2570     control.
2571
2572     \sa insert()
2573 */
2574 void QQuickTextInputPrivate::paste(QClipboard::Mode clipboardMode)
2575 {
2576     QString clip = QGuiApplication::clipboard()->text(clipboardMode);
2577     if (!clip.isEmpty() || hasSelectedText()) {
2578         separate(); //make it a separate undo/redo command
2579         insert(clip);
2580         separate();
2581     }
2582 }
2583
2584 #endif // !QT_NO_CLIPBOARD
2585
2586 /*!
2587     \internal
2588
2589     Exits preedit mode and commits parts marked as tentative commit
2590 */
2591 void QQuickTextInputPrivate::commitPreedit()
2592 {
2593     if (!composeMode())
2594         return;
2595
2596     qApp->inputPanel()->reset();
2597
2598     if (!m_tentativeCommit.isEmpty()) {
2599         internalInsert(m_tentativeCommit);
2600         m_tentativeCommit.clear();
2601         finishChange(-1, true/*not used, not documented*/, false);
2602     }
2603
2604     m_preeditCursor = 0;
2605     m_textLayout.setPreeditArea(-1, QString());
2606     m_textLayout.clearAdditionalFormats();
2607     updateLayout();
2608 }
2609
2610 /*!
2611     \internal
2612
2613     Handles the behavior for the backspace key or function.
2614     Removes the current selection if there is a selection, otherwise
2615     removes the character prior to the cursor position.
2616
2617     \sa del()
2618 */
2619 void QQuickTextInputPrivate::backspace()
2620 {
2621     int priorState = m_undoState;
2622     if (hasSelectedText()) {
2623         removeSelectedText();
2624     } else if (m_cursor) {
2625             --m_cursor;
2626             if (m_maskData)
2627                 m_cursor = prevMaskBlank(m_cursor);
2628             QChar uc = m_text.at(m_cursor);
2629             if (m_cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
2630                 // second half of a surrogate, check if we have the first half as well,
2631                 // if yes delete both at once
2632                 uc = m_text.at(m_cursor - 1);
2633                 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00) {
2634                     internalDelete(true);
2635                     --m_cursor;
2636                 }
2637             }
2638             internalDelete(true);
2639     }
2640     finishChange(priorState);
2641 }
2642
2643 /*!
2644     \internal
2645
2646     Handles the behavior for the delete key or function.
2647     Removes the current selection if there is a selection, otherwise
2648     removes the character after the cursor position.
2649
2650     \sa del()
2651 */
2652 void QQuickTextInputPrivate::del()
2653 {
2654     int priorState = m_undoState;
2655     if (hasSelectedText()) {
2656         removeSelectedText();
2657     } else {
2658         int n = m_textLayout.nextCursorPosition(m_cursor) - m_cursor;
2659         while (n--)
2660             internalDelete();
2661     }
2662     finishChange(priorState);
2663 }
2664
2665 /*!
2666     \internal
2667
2668     Inserts the given \a newText at the current cursor position.
2669     If there is any selected text it is removed prior to insertion of
2670     the new text.
2671 */
2672 void QQuickTextInputPrivate::insert(const QString &newText)
2673 {
2674     int priorState = m_undoState;
2675     removeSelectedText();
2676     internalInsert(newText);
2677     finishChange(priorState);
2678 }
2679
2680 /*!
2681     \internal
2682
2683     Clears the line control text.
2684 */
2685 void QQuickTextInputPrivate::clear()
2686 {
2687     int priorState = m_undoState;
2688     m_selstart = 0;
2689     m_selend = m_text.length();
2690     removeSelectedText();
2691     separate();
2692     finishChange(priorState, /*update*/false, /*edited*/false);
2693 }
2694
2695 /*!
2696     \internal
2697
2698     Sets \a length characters from the given \a start position as selected.
2699     The given \a start position must be within the current text for
2700     the line control.  If \a length characters cannot be selected, then
2701     the selection will extend to the end of the current text.
2702 */
2703 void QQuickTextInputPrivate::setSelection(int start, int length)
2704 {
2705     Q_Q(QQuickTextInput);
2706     commitPreedit();
2707
2708     if (start < 0 || start > (int)m_text.length()){
2709         qWarning("QQuickTextInputPrivate::setSelection: Invalid start position");
2710         return;
2711     }
2712
2713     if (length > 0) {
2714         if (start == m_selstart && start + length == m_selend && m_cursor == m_selend)
2715             return;
2716         m_selstart = start;
2717         m_selend = qMin(start + length, (int)m_text.length());
2718         m_cursor = m_selend;
2719     } else if (length < 0){
2720         if (start == m_selend && start + length == m_selstart && m_cursor == m_selstart)
2721             return;
2722         m_selstart = qMax(start + length, 0);
2723         m_selend = start;
2724         m_cursor = m_selstart;
2725     } else if (m_selstart != m_selend) {
2726         m_selstart = 0;
2727         m_selend = 0;
2728         m_cursor = start;
2729     } else {
2730         m_cursor = start;
2731         emitCursorPositionChanged();
2732         return;
2733     }
2734     emit q->selectionChanged();
2735     emitCursorPositionChanged();
2736     qApp->inputPanel()->update(Qt::ImCursorRectangle | Qt::ImAnchorPosition
2737                                | Qt::ImCursorPosition | Qt::ImCurrentSelection);
2738 }
2739
2740 /*!
2741     \internal
2742
2743     Initializes the line control with a starting text value of \a txt.
2744 */
2745 void QQuickTextInputPrivate::init(const QString &txt)
2746 {
2747     m_text = txt;
2748
2749     updateDisplayText();
2750     m_cursor = m_text.length();
2751 }
2752
2753 /*!
2754     \internal
2755
2756     Sets the password echo editing to \a editing.  If password echo editing
2757     is true, then the text of the password is displayed even if the echo
2758     mode is set to QLineEdit::PasswordEchoOnEdit.  Password echoing editing
2759     does not affect other echo modes.
2760 */
2761 void QQuickTextInputPrivate::updatePasswordEchoEditing(bool editing)
2762 {
2763     cancelPasswordEchoTimer();
2764     m_passwordEchoEditing = editing;
2765     updateDisplayText();
2766 }
2767
2768 /*!
2769     \internal
2770
2771     Fixes the current text so that it is valid given any set validators.
2772
2773     Returns true if the text was changed.  Otherwise returns false.
2774 */
2775 bool QQuickTextInputPrivate::fixup() // this function assumes that validate currently returns != Acceptable
2776 {
2777 #ifndef QT_NO_VALIDATOR
2778     if (m_validator) {
2779         QString textCopy = m_text;
2780         int cursorCopy = m_cursor;
2781         m_validator->fixup(textCopy);
2782         if (m_validator->validate(textCopy, cursorCopy) == QValidator::Acceptable) {
2783             if (textCopy != m_text || cursorCopy != m_cursor)
2784                 internalSetText(textCopy, cursorCopy);
2785             return true;
2786         }
2787     }
2788 #endif
2789     return false;
2790 }
2791
2792 /*!
2793     \internal
2794
2795     Moves the cursor to the given position \a pos.   If \a mark is true will
2796     adjust the currently selected text.
2797 */
2798 void QQuickTextInputPrivate::moveCursor(int pos, bool mark)
2799 {
2800     Q_Q(QQuickTextInput);
2801     commitPreedit();
2802
2803     if (pos != m_cursor) {
2804         separate();
2805         if (m_maskData)
2806             pos = pos > m_cursor ? nextMaskBlank(pos) : prevMaskBlank(pos);
2807     }
2808     if (mark) {
2809         int anchor;
2810         if (m_selend > m_selstart && m_cursor == m_selstart)
2811             anchor = m_selend;
2812         else if (m_selend > m_selstart && m_cursor == m_selend)
2813             anchor = m_selstart;
2814         else
2815             anchor = m_cursor;
2816         m_selstart = qMin(anchor, pos);
2817         m_selend = qMax(anchor, pos);
2818     } else {
2819         internalDeselect();
2820     }
2821     m_cursor = pos;
2822     if (mark || m_selDirty) {
2823         m_selDirty = false;
2824         emit q->selectionChanged();
2825     }
2826     emitCursorPositionChanged();
2827     q->updateMicroFocus();
2828 }
2829
2830 /*!
2831     \internal
2832
2833     Applies the given input method event \a event to the text of the line
2834     control
2835 */
2836 void QQuickTextInputPrivate::processInputMethodEvent(QInputMethodEvent *event)
2837 {
2838     Q_Q(QQuickTextInput);
2839
2840     int priorState = -1;
2841     bool isGettingInput = !event->commitString().isEmpty()
2842             || event->preeditString() != preeditAreaText()
2843             || event->replacementLength() > 0;
2844     bool cursorPositionChanged = false;
2845     bool selectionChange = false;
2846     m_preeditDirty = event->preeditString() != preeditAreaText();
2847
2848     if (isGettingInput) {
2849         // If any text is being input, remove selected text.
2850         priorState = m_undoState;
2851         if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
2852             updatePasswordEchoEditing(true);
2853             m_selstart = 0;
2854             m_selend = m_text.length();
2855         }
2856         removeSelectedText();
2857     }
2858
2859     int c = m_cursor; // cursor position after insertion of commit string
2860     if (event->replacementStart() <= 0)
2861         c += event->commitString().length() - qMin(-event->replacementStart(), event->replacementLength());
2862
2863     m_cursor += event->replacementStart();
2864     if (m_cursor < 0)
2865         m_cursor = 0;
2866
2867     // insert commit string
2868     if (event->replacementLength()) {
2869         m_selstart = m_cursor;
2870         m_selend = m_selstart + event->replacementLength();
2871         m_selend = qMin(m_selend, m_text.length());
2872         removeSelectedText();
2873     }
2874     if (!event->commitString().isEmpty()) {
2875         internalInsert(event->commitString());
2876         cursorPositionChanged = true;
2877     }
2878
2879     m_cursor = qBound(0, c, m_text.length());
2880
2881     for (int i = 0; i < event->attributes().size(); ++i) {
2882         const QInputMethodEvent::Attribute &a = event->attributes().at(i);
2883         if (a.type == QInputMethodEvent::Selection) {
2884             m_cursor = qBound(0, a.start + a.length, m_text.length());
2885             if (a.length) {
2886                 m_selstart = qMax(0, qMin(a.start, m_text.length()));
2887                 m_selend = m_cursor;
2888                 if (m_selend < m_selstart) {
2889                     qSwap(m_selstart, m_selend);
2890                 }
2891                 selectionChange = true;
2892             } else {
2893                 m_selstart = m_selend = 0;
2894             }
2895             cursorPositionChanged = true;
2896         }
2897     }
2898 #ifndef QT_NO_IM
2899     m_textLayout.setPreeditArea(m_cursor, event->preeditString());
2900 #endif //QT_NO_IM
2901     const int oldPreeditCursor = m_preeditCursor;
2902     m_preeditCursor = event->preeditString().length();
2903     m_hideCursor = false;
2904     QList<QTextLayout::FormatRange> formats;
2905     for (int i = 0; i < event->attributes().size(); ++i) {
2906         const QInputMethodEvent::Attribute &a = event->attributes().at(i);
2907         if (a.type == QInputMethodEvent::Cursor) {
2908             m_preeditCursor = a.start;
2909             m_hideCursor = !a.length;
2910         } else if (a.type == QInputMethodEvent::TextFormat) {
2911             QTextCharFormat f = qvariant_cast<QTextFormat>(a.value).toCharFormat();
2912             if (f.isValid()) {
2913                 QTextLayout::FormatRange o;
2914                 o.start = a.start + m_cursor;
2915                 o.length = a.length;
2916                 o.format = f;
2917                 formats.append(o);
2918             }
2919         }
2920     }
2921     m_textLayout.setAdditionalFormats(formats);
2922
2923     updateDisplayText(/*force*/ true);
2924     if (cursorPositionChanged) {
2925         emitCursorPositionChanged();
2926     } else if (m_preeditCursor != oldPreeditCursor) {
2927         q->updateCursorRectangle();
2928         qApp->inputPanel()->update(Qt::ImCursorRectangle);
2929     }
2930
2931     bool tentativeCommitChanged = m_tentativeCommit != event->tentativeCommitString();
2932
2933     if (tentativeCommitChanged) {
2934         m_textDirty = true;
2935         m_tentativeCommit = event->tentativeCommitString();
2936     }
2937
2938     if (isGettingInput || tentativeCommitChanged)
2939         finishChange(priorState);
2940
2941     if (selectionChange) {
2942         emit q->selectionChanged();
2943         qApp->inputPanel()->update(Qt::ImCursorRectangle | Qt::ImAnchorPosition
2944                                    | Qt::ImCursorPosition | Qt::ImCurrentSelection);
2945     }
2946 }
2947
2948 /*!
2949     \internal
2950
2951     Sets the selection to cover the word at the given cursor position.
2952     The word boundaries are defined by the behavior of QTextLayout::SkipWords
2953     cursor mode.
2954 */
2955 void QQuickTextInputPrivate::selectWordAtPos(int cursor)
2956 {
2957     int next = cursor + 1;
2958     if (next > end())
2959         --next;
2960     int c = m_textLayout.previousCursorPosition(next, QTextLayout::SkipWords);
2961     moveCursor(c, false);
2962     // ## text layout should support end of words.
2963     int end = m_textLayout.nextCursorPosition(c, QTextLayout::SkipWords);
2964     while (end > cursor && m_text[end-1].isSpace())
2965         --end;
2966     moveCursor(end, true);
2967 }
2968
2969 /*!
2970     \internal
2971
2972     Completes a change to the line control text.  If the change is not valid
2973     will undo the line control state back to the given \a validateFromState.
2974
2975     If \a edited is true and the change is valid, will emit textEdited() in
2976     addition to textChanged().  Otherwise only emits textChanged() on a valid
2977     change.
2978
2979     The \a update value is currently unused.
2980 */
2981 bool QQuickTextInputPrivate::finishChange(int validateFromState, bool update, bool /*edited*/)
2982 {
2983     Q_Q(QQuickTextInput);
2984
2985     Q_UNUSED(update)
2986     bool notifyInputPanel = m_textDirty || m_selDirty;
2987
2988     if (m_textDirty) {
2989         // do validation
2990         bool wasValidInput = m_validInput;
2991         m_validInput = true;
2992 #ifndef QT_NO_VALIDATOR
2993         if (m_validator) {
2994             QString textCopy = m_text;
2995             int cursorCopy = m_cursor;
2996             m_validInput = (m_validator->validate(textCopy, cursorCopy) != QValidator::Invalid);
2997             if (m_validInput) {
2998                 if (m_text != textCopy) {
2999                     internalSetText(textCopy, cursorCopy);
3000                     return true;
3001                 }
3002                 m_cursor = cursorCopy;
3003
3004                 if (!m_tentativeCommit.isEmpty()) {
3005                     textCopy.insert(m_cursor, m_tentativeCommit);
3006                     bool validInput = m_validator->validate(textCopy, cursorCopy) != QValidator::Invalid;
3007                     if (!validInput)
3008                         m_tentativeCommit.clear();
3009                 }
3010             } else {
3011                 m_tentativeCommit.clear();
3012             }
3013         }
3014 #endif
3015         if (validateFromState >= 0 && wasValidInput && !m_validInput) {
3016             if (m_transactions.count())
3017                 return false;
3018             internalUndo(validateFromState);
3019             m_history.resize(m_undoState);
3020             if (m_modifiedState > m_undoState)
3021                 m_modifiedState = -1;
3022             m_validInput = true;
3023             m_textDirty = false;
3024         }
3025
3026         if (m_textDirty) {
3027             m_textDirty = false;
3028             m_preeditDirty = false;
3029             determineHorizontalAlignment();
3030             emit q->textChanged();
3031         }
3032
3033         updateDisplayText();
3034
3035         if (m_validInput != wasValidInput)
3036             emit q->acceptableInputChanged();
3037     }
3038     if (m_preeditDirty) {
3039         m_preeditDirty = false;
3040         determineHorizontalAlignment();
3041     }
3042
3043     if (m_selDirty) {
3044         m_selDirty = false;
3045         emit q->selectionChanged();
3046     }
3047
3048     notifyInputPanel |= (m_cursor == m_lastCursorPos);
3049     if (notifyInputPanel)
3050         q->updateMicroFocus();
3051     emitUndoRedoChanged();
3052     emitCursorPositionChanged();
3053
3054     return true;
3055 }
3056
3057 /*!
3058     \internal
3059
3060     An internal function for setting the text of the line control.
3061 */
3062 void QQuickTextInputPrivate::internalSetText(const QString &txt, int pos, bool edited)
3063 {
3064     Q_Q(QQuickTextInput);
3065     internalDeselect();
3066     QString oldText = m_text;
3067     if (m_maskData) {
3068         m_text = maskString(0, txt, true);
3069         m_text += clearString(m_text.length(), m_maxLength - m_text.length());
3070     } else {
3071         m_text = txt.isEmpty() ? txt : txt.left(m_maxLength);
3072     }
3073     m_history.clear();
3074     m_modifiedState =  m_undoState = 0;
3075     m_cursor = (pos < 0 || pos > m_text.length()) ? m_text.length() : pos;
3076     m_textDirty = (oldText != m_text);
3077
3078     bool changed = finishChange(-1, true, edited);
3079 #ifdef QT_NO_ACCESSIBILITY
3080     Q_UNUSED(changed)
3081 #else
3082     if (changed)
3083         QAccessible::updateAccessibility(q, 0, QAccessible::TextUpdated);
3084 #endif
3085 }
3086
3087
3088 /*!
3089     \internal
3090
3091     Adds the given \a command to the undo history
3092     of the line control.  Does not apply the command.
3093 */
3094 void QQuickTextInputPrivate::addCommand(const Command &cmd)
3095 {
3096     if (m_separator && m_undoState && m_history[m_undoState - 1].type != Separator) {
3097         m_history.resize(m_undoState + 2);
3098         m_history[m_undoState++] = Command(Separator, m_cursor, 0, m_selstart, m_selend);
3099     } else {
3100         m_history.resize(m_undoState + 1);
3101     }
3102     m_separator = false;
3103     m_history[m_undoState++] = cmd;
3104 }
3105
3106 /*!
3107     \internal
3108
3109     Inserts the given string \a s into the line
3110     control.
3111
3112     Also adds the appropriate commands into the undo history.
3113     This function does not call finishChange(), and may leave the text
3114     in an invalid state.
3115 */
3116 void QQuickTextInputPrivate::internalInsert(const QString &s)
3117 {
3118 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
3119     Q_Q(QQuickTextInput);
3120     if (m_echoMode == QQuickTextInput::Password)
3121         m_passwordEchoTimer.start(qt_passwordEchoDelay, q);
3122 #endif
3123     if (hasSelectedText())
3124         addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3125     if (m_maskData) {
3126         QString ms = maskString(m_cursor, s);
3127         for (int i = 0; i < (int) ms.length(); ++i) {
3128             addCommand (Command(DeleteSelection, m_cursor + i, m_text.at(m_cursor + i), -1, -1));
3129             addCommand(Command(Insert, m_cursor + i, ms.at(i), -1, -1));
3130         }
3131         m_text.replace(m_cursor, ms.length(), ms);
3132         m_cursor += ms.length();
3133         m_cursor = nextMaskBlank(m_cursor);
3134         m_textDirty = true;
3135     } else {
3136         int remaining = m_maxLength - m_text.length();
3137         if (remaining != 0) {
3138             m_text.insert(m_cursor, s.left(remaining));
3139             for (int i = 0; i < (int) s.left(remaining).length(); ++i)
3140                addCommand(Command(Insert, m_cursor++, s.at(i), -1, -1));
3141             m_textDirty = true;
3142         }
3143     }
3144 }
3145
3146 /*!
3147     \internal
3148
3149     deletes a single character from the current text.  If \a wasBackspace,
3150     the character prior to the cursor is removed.  Otherwise the character
3151     after the cursor is removed.
3152
3153     Also adds the appropriate commands into the undo history.
3154     This function does not call finishChange(), and may leave the text
3155     in an invalid state.
3156 */
3157 void QQuickTextInputPrivate::internalDelete(bool wasBackspace)
3158 {
3159     if (m_cursor < (int) m_text.length()) {
3160         cancelPasswordEchoTimer();
3161         if (hasSelectedText())
3162             addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3163         addCommand(Command((CommandType)((m_maskData ? 2 : 0) + (wasBackspace ? Remove : Delete)),
3164                    m_cursor, m_text.at(m_cursor), -1, -1));
3165         if (m_maskData) {
3166             m_text.replace(m_cursor, 1, clearString(m_cursor, 1));
3167             addCommand(Command(Insert, m_cursor, m_text.at(m_cursor), -1, -1));
3168         } else {
3169             m_text.remove(m_cursor, 1);
3170         }
3171         m_textDirty = true;
3172     }
3173 }
3174
3175 /*!
3176     \internal
3177
3178     removes the currently selected text from the line control.
3179
3180     Also adds the appropriate commands into the undo history.
3181     This function does not call finishChange(), and may leave the text
3182     in an invalid state.
3183 */
3184 void QQuickTextInputPrivate::removeSelectedText()
3185 {
3186     if (m_selstart < m_selend && m_selend <= (int) m_text.length()) {
3187         cancelPasswordEchoTimer();
3188         separate();
3189         int i ;
3190         addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
3191         if (m_selstart <= m_cursor && m_cursor < m_selend) {
3192             // cursor is within the selection. Split up the commands
3193             // to be able to restore the correct cursor position
3194             for (i = m_cursor; i >= m_selstart; --i)
3195                 addCommand (Command(DeleteSelection, i, m_text.at(i), -1, 1));
3196             for (i = m_selend - 1; i > m_cursor; --i)
3197                 addCommand (Command(DeleteSelection, i - m_cursor + m_selstart - 1, m_text.at(i), -1, -1));
3198         } else {
3199             for (i = m_selend-1; i >= m_selstart; --i)
3200                 addCommand (Command(RemoveSelection, i, m_text.at(i), -1, -1));
3201         }
3202         if (m_maskData) {
3203             m_text.replace(m_selstart, m_selend - m_selstart,  clearString(m_selstart, m_selend - m_selstart));
3204             for (int i = 0; i < m_selend - m_selstart; ++i)
3205                 addCommand(Command(Insert, m_selstart + i, m_text.at(m_selstart + i), -1, -1));
3206         } else {
3207             m_text.remove(m_selstart, m_selend - m_selstart);
3208         }
3209         if (m_cursor > m_selstart)
3210             m_cursor -= qMin(m_cursor, m_selend) - m_selstart;
3211         internalDeselect();
3212         m_textDirty = true;
3213     }
3214 }
3215
3216 /*!
3217     \internal
3218
3219     Parses the input mask specified by \a maskFields to generate
3220     the mask data used to handle input masks.
3221 */
3222 void QQuickTextInputPrivate::parseInputMask(const QString &maskFields)
3223 {
3224     int delimiter = maskFields.indexOf(QLatin1Char(';'));
3225     if (maskFields.isEmpty() || delimiter == 0) {
3226         if (m_maskData) {
3227             delete [] m_maskData;
3228             m_maskData = 0;
3229             m_maxLength = 32767;
3230             internalSetText(QString());
3231         }
3232         return;
3233     }
3234
3235     if (delimiter == -1) {
3236         m_blank = QLatin1Char(' ');
3237         m_inputMask = maskFields;
3238     } else {
3239         m_inputMask = maskFields.left(delimiter);
3240         m_blank = (delimiter + 1 < maskFields.length()) ? maskFields[delimiter + 1] : QLatin1Char(' ');
3241     }
3242
3243     // calculate m_maxLength / m_maskData length
3244     m_maxLength = 0;
3245     QChar c = 0;
3246     for (int i=0; i<m_inputMask.length(); i++) {
3247         c = m_inputMask.at(i);
3248         if (i > 0 && m_inputMask.at(i-1) == QLatin1Char('\\')) {
3249             m_maxLength++;
3250             continue;
3251         }
3252         if (c != QLatin1Char('\\') && c != QLatin1Char('!') &&
3253              c != QLatin1Char('<') && c != QLatin1Char('>') &&
3254              c != QLatin1Char('{') && c != QLatin1Char('}') &&
3255              c != QLatin1Char('[') && c != QLatin1Char(']'))
3256             m_maxLength++;
3257     }
3258
3259     delete [] m_maskData;
3260     m_maskData = new MaskInputData[m_maxLength];
3261
3262     MaskInputData::Casemode m = MaskInputData::NoCaseMode;
3263     c = 0;
3264     bool s;
3265     bool escape = false;
3266     int index = 0;
3267     for (int i = 0; i < m_inputMask.length(); i++) {
3268         c = m_inputMask.at(i);
3269         if (escape) {
3270             s = true;
3271             m_maskData[index].maskChar = c;
3272             m_maskData[index].separator = s;
3273             m_maskData[index].caseMode = m;
3274             index++;
3275             escape = false;
3276         } else if (c == QLatin1Char('<')) {
3277                 m = MaskInputData::Lower;
3278         } else if (c == QLatin1Char('>')) {
3279             m = MaskInputData::Upper;
3280         } else if (c == QLatin1Char('!')) {
3281             m = MaskInputData::NoCaseMode;
3282         } else if (c != QLatin1Char('{') && c != QLatin1Char('}') && c != QLatin1Char('[') && c != QLatin1Char(']')) {
3283             switch (c.unicode()) {
3284             case 'A':
3285             case 'a':
3286             case 'N':
3287             case 'n':
3288             case 'X':
3289             case 'x':
3290             case '9':
3291             case '0':
3292             case 'D':
3293             case 'd':
3294             case '#':
3295             case 'H':
3296             case 'h':
3297             case 'B':
3298             case 'b':
3299                 s = false;
3300                 break;
3301             case '\\':
3302                 escape = true;
3303             default:
3304                 s = true;
3305                 break;
3306             }
3307
3308             if (!escape) {
3309                 m_maskData[index].maskChar = c;
3310                 m_maskData[index].separator = s;
3311                 m_maskData[index].caseMode = m;
3312                 index++;
3313             }
3314         }
3315     }
3316     internalSetText(m_text);
3317 }
3318
3319
3320 /*!
3321     \internal
3322
3323     checks if the key is valid compared to the inputMask
3324 */
3325 bool QQuickTextInputPrivate::isValidInput(QChar key, QChar mask) const
3326 {
3327     switch (mask.unicode()) {
3328     case 'A':
3329         if (key.isLetter())
3330             return true;
3331         break;
3332     case 'a':
3333         if (key.isLetter() || key == m_blank)
3334             return true;
3335         break;
3336     case 'N':
3337         if (key.isLetterOrNumber())
3338             return true;
3339         break;
3340     case 'n':
3341         if (key.isLetterOrNumber() || key == m_blank)
3342             return true;
3343         break;
3344     case 'X':
3345         if (key.isPrint())
3346             return true;
3347         break;
3348     case 'x':
3349         if (key.isPrint() || key == m_blank)
3350             return true;
3351         break;
3352     case '9':
3353         if (key.isNumber())
3354             return true;
3355         break;
3356     case '0':
3357         if (key.isNumber() || key == m_blank)
3358             return true;
3359         break;
3360     case 'D':
3361         if (key.isNumber() && key.digitValue() > 0)
3362             return true;
3363         break;
3364     case 'd':
3365         if ((key.isNumber() && key.digitValue() > 0) || key == m_blank)
3366             return true;
3367         break;
3368     case '#':
3369         if (key.isNumber() || key == QLatin1Char('+') || key == QLatin1Char('-') || key == m_blank)
3370             return true;
3371         break;
3372     case 'B':
3373         if (key == QLatin1Char('0') || key == QLatin1Char('1'))
3374             return true;
3375         break;
3376     case 'b':
3377         if (key == QLatin1Char('0') || key == QLatin1Char('1') || key == m_blank)
3378             return true;
3379         break;
3380     case 'H':
3381         if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')))
3382             return true;
3383         break;
3384     case 'h':
3385         if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')) || key == m_blank)
3386             return true;
3387         break;
3388     default:
3389         break;
3390     }
3391     return false;
3392 }
3393
3394 /*!
3395     \internal
3396
3397     Returns true if the given text \a str is valid for any
3398     validator or input mask set for the line control.
3399
3400     Otherwise returns false
3401 */
3402 bool QQuickTextInputPrivate::hasAcceptableInput(const QString &str) const
3403 {
3404 #ifndef QT_NO_VALIDATOR
3405     QString textCopy = str;
3406     int cursorCopy = m_cursor;
3407     if (m_validator && m_validator->validate(textCopy, cursorCopy)
3408         != QValidator::Acceptable)
3409         return false;
3410 #endif
3411
3412     if (!m_maskData)
3413         return true;
3414
3415     if (str.length() != m_maxLength)
3416         return false;
3417
3418     for (int i=0; i < m_maxLength; ++i) {
3419         if (m_maskData[i].separator) {
3420             if (str.at(i) != m_maskData[i].maskChar)
3421                 return false;
3422         } else {
3423             if (!isValidInput(str.at(i), m_maskData[i].maskChar))
3424                 return false;
3425         }
3426     }
3427     return true;
3428 }
3429
3430 /*!
3431     \internal
3432
3433     Applies the inputMask on \a str starting from position \a pos in the mask. \a clear
3434     specifies from where characters should be gotten when a separator is met in \a str - true means
3435     that blanks will be used, false that previous input is used.
3436     Calling this when no inputMask is set is undefined.
3437 */
3438 QString QQuickTextInputPrivate::maskString(uint pos, const QString &str, bool clear) const
3439 {
3440     if (pos >= (uint)m_maxLength)
3441         return QString::fromLatin1("");
3442
3443     QString fill;
3444     fill = clear ? clearString(0, m_maxLength) : m_text;
3445
3446     int strIndex = 0;
3447     QString s = QString::fromLatin1("");
3448     int i = pos;
3449     while (i < m_maxLength) {
3450         if (strIndex < str.length()) {
3451             if (m_maskData[i].separator) {
3452                 s += m_maskData[i].maskChar;
3453                 if (str[(int)strIndex] == m_maskData[i].maskChar)
3454                     strIndex++;
3455                 ++i;
3456             } else {
3457                 if (isValidInput(str[(int)strIndex], m_maskData[i].maskChar)) {
3458                     switch (m_maskData[i].caseMode) {
3459                     case MaskInputData::Upper:
3460                         s += str[(int)strIndex].toUpper();
3461                         break;
3462                     case MaskInputData::Lower:
3463                         s += str[(int)strIndex].toLower();
3464                         break;
3465                     default:
3466                         s += str[(int)strIndex];
3467                     }
3468                     ++i;
3469                 } else {
3470                     // search for separator first
3471                     int n = findInMask(i, true, true, str[(int)strIndex]);
3472                     if (n != -1) {
3473                         if (str.length() != 1 || i == 0 || (i > 0 && (!m_maskData[i-1].separator || m_maskData[i-1].maskChar != str[(int)strIndex]))) {
3474                             s += fill.mid(i, n-i+1);
3475                             i = n + 1; // update i to find + 1
3476                         }
3477                     } else {
3478                         // search for valid m_blank if not
3479                         n = findInMask(i, true, false, str[(int)strIndex]);
3480                         if (n != -1) {
3481                             s += fill.mid(i, n-i);
3482                             switch (m_maskData[n].caseMode) {
3483                             case MaskInputData::Upper:
3484                                 s += str[(int)strIndex].toUpper();
3485                                 break;
3486                             case MaskInputData::Lower:
3487                                 s += str[(int)strIndex].toLower();
3488                                 break;
3489                             default:
3490                                 s += str[(int)strIndex];
3491                             }
3492                             i = n + 1; // updates i to find + 1
3493                         }
3494                     }
3495                 }
3496                 ++strIndex;
3497             }
3498         } else
3499             break;
3500     }
3501
3502     return s;
3503 }
3504
3505
3506
3507 /*!
3508     \internal
3509
3510     Returns a "cleared" string with only separators and blank chars.
3511     Calling this when no inputMask is set is undefined.
3512 */
3513 QString QQuickTextInputPrivate::clearString(uint pos, uint len) const
3514 {
3515     if (pos >= (uint)m_maxLength)
3516         return QString();
3517
3518     QString s;
3519     int end = qMin((uint)m_maxLength, pos + len);
3520     for (int i = pos; i < end; ++i)
3521         if (m_maskData[i].separator)
3522             s += m_maskData[i].maskChar;
3523         else
3524             s += m_blank;
3525
3526     return s;
3527 }
3528
3529 /*!
3530     \internal
3531
3532     Strips blank parts of the input in a QQuickTextInputPrivate when an inputMask is set,
3533     separators are still included. Typically "127.0__.0__.1__" becomes "127.0.0.1".
3534 */
3535 QString QQuickTextInputPrivate::stripString(const QString &str) const
3536 {
3537     if (!m_maskData)
3538         return str;
3539
3540     QString s;
3541     int end = qMin(m_maxLength, (int)str.length());
3542     for (int i = 0; i < end; ++i) {
3543         if (m_maskData[i].separator)
3544             s += m_maskData[i].maskChar;
3545         else if (str[i] != m_blank)
3546             s += str[i];
3547     }
3548
3549     return s;
3550 }
3551
3552 /*!
3553     \internal
3554     searches forward/backward in m_maskData for either a separator or a m_blank
3555 */
3556 int QQuickTextInputPrivate::findInMask(int pos, bool forward, bool findSeparator, QChar searchChar) const
3557 {
3558     if (pos >= m_maxLength || pos < 0)
3559         return -1;
3560
3561     int end = forward ? m_maxLength : -1;
3562     int step = forward ? 1 : -1;
3563     int i = pos;
3564
3565     while (i != end) {
3566         if (findSeparator) {
3567             if (m_maskData[i].separator && m_maskData[i].maskChar == searchChar)
3568                 return i;
3569         } else {
3570             if (!m_maskData[i].separator) {
3571                 if (searchChar.isNull())
3572                     return i;
3573                 else if (isValidInput(searchChar, m_maskData[i].maskChar))
3574                     return i;
3575             }
3576         }
3577         i += step;
3578     }
3579     return -1;
3580 }
3581
3582 void QQuickTextInputPrivate::internalUndo(int until)
3583 {
3584     if (!isUndoAvailable())
3585         return;
3586     cancelPasswordEchoTimer();
3587     internalDeselect();
3588     while (m_undoState && m_undoState > until) {
3589         Command& cmd = m_history[--m_undoState];
3590         switch (cmd.type) {
3591         case Insert:
3592             m_text.remove(cmd.pos, 1);
3593             m_cursor = cmd.pos;
3594             break;
3595         case SetSelection:
3596             m_selstart = cmd.selStart;
3597             m_selend = cmd.selEnd;
3598             m_cursor = cmd.pos;
3599             break;
3600         case Remove:
3601         case RemoveSelection:
3602             m_text.insert(cmd.pos, cmd.uc);
3603             m_cursor = cmd.pos + 1;
3604             break;
3605         case Delete:
3606         case DeleteSelection:
3607             m_text.insert(cmd.pos, cmd.uc);
3608             m_cursor = cmd.pos;
3609             break;
3610         case Separator:
3611             continue;
3612         }
3613         if (until < 0 && m_undoState) {
3614             Command& next = m_history[m_undoState-1];
3615             if (next.type != cmd.type && next.type < RemoveSelection
3616                  && (cmd.type < RemoveSelection || next.type == Separator))
3617                 break;
3618         }
3619     }
3620     m_textDirty = true;
3621 }
3622
3623 void QQuickTextInputPrivate::internalRedo()
3624 {
3625     if (!isRedoAvailable())
3626         return;
3627     internalDeselect();
3628     while (m_undoState < (int)m_history.size()) {
3629         Command& cmd = m_history[m_undoState++];
3630         switch (cmd.type) {
3631         case Insert:
3632             m_text.insert(cmd.pos, cmd.uc);
3633             m_cursor = cmd.pos + 1;
3634             break;
3635         case SetSelection:
3636             m_selstart = cmd.selStart;
3637             m_selend = cmd.selEnd;
3638             m_cursor = cmd.pos;
3639             break;
3640         case Remove:
3641         case Delete:
3642         case RemoveSelection:
3643         case DeleteSelection:
3644             m_text.remove(cmd.pos, 1);
3645             m_selstart = cmd.selStart;
3646             m_selend = cmd.selEnd;
3647             m_cursor = cmd.pos;
3648             break;
3649         case Separator:
3650             m_selstart = cmd.selStart;
3651             m_selend = cmd.selEnd;
3652             m_cursor = cmd.pos;
3653             break;
3654         }
3655         if (m_undoState < (int)m_history.size()) {
3656             Command& next = m_history[m_undoState];
3657             if (next.type != cmd.type && cmd.type < RemoveSelection && next.type != Separator
3658                  && (next.type < RemoveSelection || cmd.type == Separator))
3659                 break;
3660         }
3661     }
3662     m_textDirty = true;
3663 }
3664
3665 void QQuickTextInputPrivate::emitUndoRedoChanged()
3666 {
3667     Q_Q(QQuickTextInput);
3668     const bool previousUndo = canUndo;
3669     const bool previousRedo = canRedo;
3670
3671     canUndo = isUndoAvailable();
3672     canRedo = isRedoAvailable();
3673
3674     if (previousUndo != canUndo)
3675         emit q->canUndoChanged();
3676     if (previousRedo != canRedo)
3677         emit q->canRedoChanged();
3678 }
3679
3680 /*!
3681     \internal
3682
3683     If the current cursor position differs from the last emitted cursor
3684     position, emits cursorPositionChanged().
3685 */
3686 void QQuickTextInputPrivate::emitCursorPositionChanged()
3687 {
3688     Q_Q(QQuickTextInput);
3689     if (m_cursor != m_lastCursorPos) {
3690         m_lastCursorPos = m_cursor;
3691
3692         q->updateCursorRectangle();
3693         emit q->cursorPositionChanged();
3694         // XXX todo - not in 4.8?
3695     #if 0
3696         resetCursorBlinkTimer();
3697     #endif
3698
3699         if (!hasSelectedText()) {
3700             if (lastSelectionStart != m_cursor) {
3701                 lastSelectionStart = m_cursor;
3702                 emit q->selectionStartChanged();
3703             }
3704             if (lastSelectionEnd != m_cursor) {
3705                 lastSelectionEnd = m_cursor;
3706                 emit q->selectionEndChanged();
3707             }
3708         }
3709
3710 #ifndef QT_NO_ACCESSIBILITY
3711         QAccessible::updateAccessibility(q, 0, QAccessible::TextCaretMoved);
3712 #endif
3713     }
3714 }
3715
3716
3717 void QQuickTextInputPrivate::setCursorBlinkPeriod(int msec)
3718 {
3719     Q_Q(QQuickTextInput);
3720     if (msec == m_blinkPeriod)
3721         return;
3722     if (m_blinkTimer) {
3723         q->killTimer(m_blinkTimer);
3724     }
3725     if (msec) {
3726         m_blinkTimer = q->startTimer(msec / 2);
3727         m_blinkStatus = 1;
3728     } else {
3729         m_blinkTimer = 0;
3730         if (m_blinkStatus == 1)
3731             q->update();
3732     }
3733     m_blinkPeriod = msec;
3734 }
3735
3736 void QQuickTextInputPrivate::resetCursorBlinkTimer()
3737 {
3738     Q_Q(QQuickTextInput);
3739     if (m_blinkPeriod == 0 || m_blinkTimer == 0)
3740         return;
3741     q->killTimer(m_blinkTimer);
3742     m_blinkTimer = q->startTimer(m_blinkPeriod / 2);
3743     m_blinkStatus = 1;
3744 }
3745
3746 void QQuickTextInput::timerEvent(QTimerEvent *event)
3747 {
3748     Q_D(QQuickTextInput);
3749     if (event->timerId() == d->m_blinkTimer) {
3750         d->m_blinkStatus = !d->m_blinkStatus;
3751         update();
3752     } else if (event->timerId() == d->m_deleteAllTimer) {
3753         killTimer(d->m_deleteAllTimer);
3754         d->m_deleteAllTimer = 0;
3755         d->clear();
3756 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
3757     } else if (event->timerId() == d->m_passwordEchoTimer.timerId()) {
3758         d->m_passwordEchoTimer.stop();
3759         d->updateDisplayText();
3760 #endif
3761     }
3762 }
3763
3764 void QQuickTextInputPrivate::processKeyEvent(QKeyEvent* event)
3765 {
3766     Q_Q(QQuickTextInput);
3767     bool inlineCompletionAccepted = false;
3768
3769     if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) {
3770         if (hasAcceptableInput(m_text) || fixup()) {
3771             emit q->accepted();
3772         }
3773         if (inlineCompletionAccepted)
3774             event->accept();
3775         else
3776             event->ignore();
3777         return;
3778     }
3779
3780     if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit
3781         && !m_passwordEchoEditing
3782         && !m_readOnly
3783         && !event->text().isEmpty()
3784         && !(event->modifiers() & Qt::ControlModifier)) {
3785         // Clear the edit and reset to normal echo mode while editing; the
3786         // echo mode switches back when the edit loses focus
3787         // ### resets current content.  dubious code; you can
3788         // navigate with keys up, down, back, and select(?), but if you press
3789         // "left" or "right" it clears?
3790         updatePasswordEchoEditing(true);
3791         clear();
3792     }
3793
3794     bool unknown = false;
3795     bool visual = cursorMoveStyle() == Qt::VisualMoveStyle;
3796
3797     if (false) {
3798     }
3799 #ifndef QT_NO_SHORTCUT
3800     else if (event == QKeySequence::Undo) {
3801         if (!m_readOnly)
3802             q->undo();
3803     }
3804     else if (event == QKeySequence::Redo) {
3805         if (!m_readOnly)
3806             q->redo();
3807     }
3808     else if (event == QKeySequence::SelectAll) {
3809         selectAll();
3810     }
3811 #ifndef QT_NO_CLIPBOARD
3812     else if (event == QKeySequence::Copy) {
3813         copy();
3814     }
3815     else if (event == QKeySequence::Paste) {
3816         if (!m_readOnly) {
3817             QClipboard::Mode mode = QClipboard::Clipboard;
3818             paste(mode);
3819         }
3820     }
3821     else if (event == QKeySequence::Cut) {
3822         if (!m_readOnly) {
3823             copy();
3824             del();
3825         }
3826     }
3827     else if (event == QKeySequence::DeleteEndOfLine) {
3828         if (!m_readOnly) {
3829             setSelection(m_cursor, end());
3830             copy();
3831             del();
3832         }
3833     }
3834 #endif //QT_NO_CLIPBOARD
3835     else if (event == QKeySequence::MoveToStartOfLine || event == QKeySequence::MoveToStartOfBlock) {
3836         home(0);
3837     }
3838     else if (event == QKeySequence::MoveToEndOfLine || event == QKeySequence::MoveToEndOfBlock) {
3839         end(0);
3840     }
3841     else if (event == QKeySequence::SelectStartOfLine || event == QKeySequence::SelectStartOfBlock) {
3842         home(1);
3843     }
3844     else if (event == QKeySequence::SelectEndOfLine || event == QKeySequence::SelectEndOfBlock) {
3845         end(1);
3846     }
3847     else if (event == QKeySequence::MoveToNextChar) {
3848         if (hasSelectedText()) {
3849             moveCursor(selectionEnd(), false);
3850         } else {
3851             cursorForward(0, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
3852         }
3853     }
3854     else if (event == QKeySequence::SelectNextChar) {
3855         cursorForward(1, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
3856     }
3857     else if (event == QKeySequence::MoveToPreviousChar) {
3858         if (hasSelectedText()) {
3859             moveCursor(selectionStart(), false);
3860         } else {
3861             cursorForward(0, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
3862         }
3863     }
3864     else if (event == QKeySequence::SelectPreviousChar) {
3865         cursorForward(1, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
3866     }
3867     else if (event == QKeySequence::MoveToNextWord) {
3868         if (m_echoMode == QQuickTextInput::Normal)
3869             layoutDirection() == Qt::LeftToRight ? cursorWordForward(0) : cursorWordBackward(0);
3870         else
3871             layoutDirection() == Qt::LeftToRight ? end(0) : home(0);
3872     }
3873     else if (event == QKeySequence::MoveToPreviousWord) {
3874         if (m_echoMode == QQuickTextInput::Normal)
3875             layoutDirection() == Qt::LeftToRight ? cursorWordBackward(0) : cursorWordForward(0);
3876         else if (!m_readOnly) {
3877             layoutDirection() == Qt::LeftToRight ? home(0) : end(0);
3878         }
3879     }
3880     else if (event == QKeySequence::SelectNextWord) {
3881         if (m_echoMode == QQuickTextInput::Normal)
3882             layoutDirection() == Qt::LeftToRight ? cursorWordForward(1) : cursorWordBackward(1);
3883         else
3884             layoutDirection() == Qt::LeftToRight ? end(1) : home(1);
3885     }
3886     else if (event == QKeySequence::SelectPreviousWord) {
3887         if (m_echoMode == QQuickTextInput::Normal)
3888             layoutDirection() == Qt::LeftToRight ? cursorWordBackward(1) : cursorWordForward(1);
3889         else
3890             layoutDirection() == Qt::LeftToRight ? home(1) : end(1);
3891     }
3892     else if (event == QKeySequence::Delete) {
3893         if (!m_readOnly)
3894             del();
3895     }
3896     else if (event == QKeySequence::DeleteEndOfWord) {
3897         if (!m_readOnly) {
3898             cursorWordForward(true);
3899             del();
3900         }
3901     }
3902     else if (event == QKeySequence::DeleteStartOfWord) {
3903         if (!m_readOnly) {
3904             cursorWordBackward(true);
3905             del();
3906         }
3907     }
3908 #endif // QT_NO_SHORTCUT
3909     else {
3910         bool handled = false;
3911         if (event->modifiers() & Qt::ControlModifier) {
3912             switch (event->key()) {
3913             case Qt::Key_Backspace:
3914                 if (!m_readOnly) {
3915                     cursorWordBackward(true);
3916                     del();
3917                 }
3918                 break;
3919             default:
3920                 if (!handled)
3921                     unknown = true;
3922             }
3923         } else { // ### check for *no* modifier
3924             switch (event->key()) {
3925             case Qt::Key_Backspace:
3926                 if (!m_readOnly) {
3927                     backspace();
3928                 }
3929                 break;
3930             default:
3931                 if (!handled)
3932                     unknown = true;
3933             }
3934         }
3935     }
3936
3937     if (event->key() == Qt::Key_Direction_L || event->key() == Qt::Key_Direction_R) {
3938         setLayoutDirection((event->key() == Qt::Key_Direction_L) ? Qt::LeftToRight : Qt::RightToLeft);
3939         unknown = false;
3940     }
3941
3942     if (unknown && !m_readOnly) {
3943         QString t = event->text();
3944         if (!t.isEmpty() && t.at(0).isPrint()) {
3945             insert(t);
3946             event->accept();
3947             return;
3948         }
3949     }
3950
3951     if (unknown)
3952         event->ignore();
3953     else
3954         event->accept();
3955 }
3956
3957
3958 QT_END_NAMESPACE
3959