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