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