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