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