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