Create a copy of QLineControl in the QtDeclarative library.
[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 QT_BEGIN_NAMESPACE
58
59 DEFINE_BOOL_CONFIG_OPTION(qmlDisableDistanceField, QML_DISABLE_DISTANCEFIELD)
60
61 /*!
62     \qmlclass TextInput QQuickTextInput
63     \inqmlmodule QtQuick 2
64     \ingroup qml-basic-visual-elements
65     \brief The TextInput item displays an editable line of text.
66     \inherits Item
67
68     The TextInput element displays a single line of editable plain text.
69
70     TextInput is used to accept a line of text input. Input constraints
71     can be placed on a TextInput item (for example, through a \l validator or \l inputMask),
72     and setting \l echoMode to an appropriate value enables TextInput to be used for
73     a password input field.
74
75     On Mac OS X, the Up/Down key bindings for Home/End are explicitly disabled.
76     If you want such bindings (on any platform), you will need to construct them in QML.
77
78     \sa TextEdit, Text, {declarative/text/textselection}{Text Selection example}
79 */
80 QQuickTextInput::QQuickTextInput(QQuickItem* parent)
81 : QQuickImplicitSizeItem(*(new QQuickTextInputPrivate), parent)
82 {
83     Q_D(QQuickTextInput);
84     d->init();
85 }
86
87 QQuickTextInput::~QQuickTextInput()
88 {
89 }
90
91 /*!
92     \qmlproperty string QtQuick2::TextInput::text
93
94     The text in the TextInput.
95 */
96 QString QQuickTextInput::text() const
97 {
98     Q_D(const QQuickTextInput);
99     return d->control->text();
100 }
101
102 void QQuickTextInput::setText(const QString &s)
103 {
104     Q_D(QQuickTextInput);
105     if (s == text())
106         return;
107     d->control->setText(s);
108 }
109
110 /*!
111     \qmlproperty string QtQuick2::TextInput::font.family
112
113     Sets the family name of the font.
114
115     The family name is case insensitive and may optionally include a foundry name, e.g. "Helvetica [Cronyx]".
116     If the family is available from more than one foundry and the foundry isn't specified, an arbitrary foundry is chosen.
117     If the family isn't available a family will be set using the font matching algorithm.
118 */
119
120 /*!
121     \qmlproperty bool QtQuick2::TextInput::font.bold
122
123     Sets whether the font weight is bold.
124 */
125
126 /*!
127     \qmlproperty enumeration QtQuick2::TextInput::font.weight
128
129     Sets the font's weight.
130
131     The weight can be one of:
132     \list
133     \o Font.Light
134     \o Font.Normal - the default
135     \o Font.DemiBold
136     \o Font.Bold
137     \o Font.Black
138     \endlist
139
140     \qml
141     TextInput { text: "Hello"; font.weight: Font.DemiBold }
142     \endqml
143 */
144
145 /*!
146     \qmlproperty bool QtQuick2::TextInput::font.italic
147
148     Sets whether the font has an italic style.
149 */
150
151 /*!
152     \qmlproperty bool QtQuick2::TextInput::font.underline
153
154     Sets whether the text is underlined.
155 */
156
157 /*!
158     \qmlproperty bool QtQuick2::TextInput::font.strikeout
159
160     Sets whether the font has a strikeout style.
161 */
162
163 /*!
164     \qmlproperty real QtQuick2::TextInput::font.pointSize
165
166     Sets the font size in points. The point size must be greater than zero.
167 */
168
169 /*!
170     \qmlproperty int QtQuick2::TextInput::font.pixelSize
171
172     Sets the font size in pixels.
173
174     Using this function makes the font device dependent.
175     Use \c pointSize to set the size of the font in a device independent manner.
176 */
177
178 /*!
179     \qmlproperty real QtQuick2::TextInput::font.letterSpacing
180
181     Sets the letter spacing for the font.
182
183     Letter spacing changes the default spacing between individual letters in the font.
184     A positive value increases the letter spacing by the corresponding pixels; a negative value decreases the spacing.
185 */
186
187 /*!
188     \qmlproperty real QtQuick2::TextInput::font.wordSpacing
189
190     Sets the word spacing for the font.
191
192     Word spacing changes the default spacing between individual words.
193     A positive value increases the word spacing by a corresponding amount of pixels,
194     while a negative value decreases the inter-word spacing accordingly.
195 */
196
197 /*!
198     \qmlproperty enumeration QtQuick2::TextInput::font.capitalization
199
200     Sets the capitalization for the text.
201
202     \list
203     \o Font.MixedCase - This is the normal text rendering option where no capitalization change is applied.
204     \o Font.AllUppercase - This alters the text to be rendered in all uppercase type.
205     \o Font.AllLowercase - This alters the text to be rendered in all lowercase type.
206     \o Font.SmallCaps - This alters the text to be rendered in small-caps type.
207     \o Font.Capitalize - This alters the text to be rendered with the first character of each word as an uppercase character.
208     \endlist
209
210     \qml
211     TextInput { text: "Hello"; font.capitalization: Font.AllLowercase }
212     \endqml
213 */
214
215 QFont QQuickTextInput::font() const
216 {
217     Q_D(const QQuickTextInput);
218     return d->sourceFont;
219 }
220
221 void QQuickTextInput::setFont(const QFont &font)
222 {
223     Q_D(QQuickTextInput);
224     if (d->sourceFont == font)
225         return;
226
227     d->sourceFont = font;
228     QFont oldFont = d->font;
229     d->font = font;
230     if (d->font.pointSizeF() != -1) {
231         // 0.5pt resolution
232         qreal size = qRound(d->font.pointSizeF()*2.0);
233         d->font.setPointSizeF(size/2.0);
234     }
235     if (oldFont != d->font) {
236         d->control->setFont(d->font);
237         updateSize();
238         updateCursorRectangle();
239         if (d->cursorItem) {
240             d->cursorItem->setHeight(QFontMetrics(d->font).height());
241         }
242     }
243     emit fontChanged(d->sourceFont);
244 }
245
246 /*!
247     \qmlproperty color QtQuick2::TextInput::color
248
249     The text color.
250 */
251 QColor QQuickTextInput::color() const
252 {
253     Q_D(const QQuickTextInput);
254     return d->color;
255 }
256
257 void QQuickTextInput::setColor(const QColor &c)
258 {
259     Q_D(QQuickTextInput);
260     if (c != d->color) {
261         d->color = c;
262         d->textLayoutDirty = true;
263         update();
264         emit colorChanged(c);
265     }
266 }
267
268
269 /*!
270     \qmlproperty color QtQuick2::TextInput::selectionColor
271
272     The text highlight color, used behind selections.
273 */
274 QColor QQuickTextInput::selectionColor() const
275 {
276     Q_D(const QQuickTextInput);
277     return d->selectionColor;
278 }
279
280 void QQuickTextInput::setSelectionColor(const QColor &color)
281 {
282     Q_D(QQuickTextInput);
283     if (d->selectionColor == color)
284         return;
285
286     d->selectionColor = color;
287     QPalette p = d->control->palette();
288     p.setColor(QPalette::Highlight, d->selectionColor);
289     d->control->setPalette(p);
290     if (d->control->hasSelectedText()) {
291         d->textLayoutDirty = true;
292         update();
293     }
294     emit selectionColorChanged(color);
295 }
296 /*!
297     \qmlproperty color QtQuick2::TextInput::selectedTextColor
298
299     The highlighted text color, used in selections.
300 */
301 QColor QQuickTextInput::selectedTextColor() const
302 {
303     Q_D(const QQuickTextInput);
304     return d->selectedTextColor;
305 }
306
307 void QQuickTextInput::setSelectedTextColor(const QColor &color)
308 {
309     Q_D(QQuickTextInput);
310     if (d->selectedTextColor == color)
311         return;
312
313     d->selectedTextColor = color;
314     QPalette p = d->control->palette();
315     p.setColor(QPalette::HighlightedText, d->selectedTextColor);
316     d->control->setPalette(p);
317     if (d->control->hasSelectedText()) {
318         d->textLayoutDirty = true;
319         update();
320     }
321     emit selectedTextColorChanged(color);
322 }
323
324 /*!
325     \qmlproperty enumeration QtQuick2::TextInput::horizontalAlignment
326     \qmlproperty enumeration QtQuick2::TextInput::effectiveHorizontalAlignment
327
328     Sets the horizontal alignment of the text within the TextInput item's
329     width and height. By default, the text alignment follows the natural alignment
330     of the text, for example text that is read from left to right will be aligned to
331     the left.
332
333     TextInput does not have vertical alignment, as the natural height is
334     exactly the height of the single line of text. If you set the height
335     manually to something larger, TextInput will always be top aligned
336     vertically. You can use anchors to align it however you want within
337     another item.
338
339     The valid values for \c horizontalAlignment are \c TextInput.AlignLeft, \c TextInput.AlignRight and
340     \c TextInput.AlignHCenter.
341
342     When using the attached property LayoutMirroring::enabled to mirror application
343     layouts, the horizontal alignment of text will also be mirrored. However, the property
344     \c horizontalAlignment will remain unchanged. To query the effective horizontal alignment
345     of TextInput, use the read-only property \c effectiveHorizontalAlignment.
346 */
347 QQuickTextInput::HAlignment QQuickTextInput::hAlign() const
348 {
349     Q_D(const QQuickTextInput);
350     return d->hAlign;
351 }
352
353 void QQuickTextInput::setHAlign(HAlignment align)
354 {
355     Q_D(QQuickTextInput);
356     bool forceAlign = d->hAlignImplicit && d->effectiveLayoutMirror;
357     d->hAlignImplicit = false;
358     if (d->setHAlign(align, forceAlign) && isComponentComplete()) {
359         updateCursorRectangle();
360     }
361 }
362
363 void QQuickTextInput::resetHAlign()
364 {
365     Q_D(QQuickTextInput);
366     d->hAlignImplicit = true;
367     if (d->determineHorizontalAlignment() && isComponentComplete()) {
368         updateCursorRectangle();
369     }
370 }
371
372 QQuickTextInput::HAlignment QQuickTextInput::effectiveHAlign() const
373 {
374     Q_D(const QQuickTextInput);
375     QQuickTextInput::HAlignment effectiveAlignment = d->hAlign;
376     if (!d->hAlignImplicit && d->effectiveLayoutMirror) {
377         switch (d->hAlign) {
378         case QQuickTextInput::AlignLeft:
379             effectiveAlignment = QQuickTextInput::AlignRight;
380             break;
381         case QQuickTextInput::AlignRight:
382             effectiveAlignment = QQuickTextInput::AlignLeft;
383             break;
384         default:
385             break;
386         }
387     }
388     return effectiveAlignment;
389 }
390
391 bool QQuickTextInputPrivate::setHAlign(QQuickTextInput::HAlignment alignment, bool forceAlign)
392 {
393     Q_Q(QQuickTextInput);
394     if ((hAlign != alignment || forceAlign) && alignment <= QQuickTextInput::AlignHCenter) { // justify not supported
395         QQuickTextInput::HAlignment oldEffectiveHAlign = q->effectiveHAlign();
396         hAlign = alignment;
397         emit q->horizontalAlignmentChanged(alignment);
398         if (oldEffectiveHAlign != q->effectiveHAlign())
399             emit q->effectiveHorizontalAlignmentChanged();
400         return true;
401     }
402     return false;
403 }
404
405 bool QQuickTextInputPrivate::determineHorizontalAlignment()
406 {
407     if (hAlignImplicit) {
408         // if no explicit alignment has been set, follow the natural layout direction of the text
409         QString text = control->text();
410         if (text.isEmpty())
411             text = control->preeditAreaText();
412         bool isRightToLeft = text.isEmpty() ? QGuiApplication::keyboardInputDirection() == Qt::RightToLeft : text.isRightToLeft();
413         return setHAlign(isRightToLeft ? QQuickTextInput::AlignRight : QQuickTextInput::AlignLeft);
414     }
415     return false;
416 }
417
418 void QQuickTextInputPrivate::mirrorChange()
419 {
420     Q_Q(QQuickTextInput);
421     if (q->isComponentComplete()) {
422         if (!hAlignImplicit && (hAlign == QQuickTextInput::AlignRight || hAlign == QQuickTextInput::AlignLeft)) {
423             q->updateCursorRectangle();
424             emit q->effectiveHorizontalAlignmentChanged();
425         }
426     }
427 }
428
429 /*!
430     \qmlproperty bool QtQuick2::TextInput::readOnly
431
432     Sets whether user input can modify the contents of the TextInput.
433
434     If readOnly is set to true, then user input will not affect the text
435     property. Any bindings or attempts to set the text property will still
436     work.
437 */
438 bool QQuickTextInput::isReadOnly() const
439 {
440     Q_D(const QQuickTextInput);
441     return d->control->isReadOnly();
442 }
443
444 void QQuickTextInput::setReadOnly(bool ro)
445 {
446     Q_D(QQuickTextInput);
447     if (d->control->isReadOnly() == ro)
448         return;
449
450     setFlag(QQuickItem::ItemAcceptsInputMethod, !ro);
451     d->control->setReadOnly(ro);
452     if (!ro)
453         d->control->setCursorPosition(d->control->end());
454
455     emit readOnlyChanged(ro);
456 }
457
458 /*!
459     \qmlproperty int QtQuick2::TextInput::maximumLength
460     The maximum permitted length of the text in the TextInput.
461
462     If the text is too long, it is truncated at the limit.
463
464     By default, this property contains a value of 32767.
465 */
466 int QQuickTextInput::maxLength() const
467 {
468     Q_D(const QQuickTextInput);
469     return d->control->maxLength();
470 }
471
472 void QQuickTextInput::setMaxLength(int ml)
473 {
474     Q_D(QQuickTextInput);
475     if (d->control->maxLength() == ml)
476         return;
477
478     d->control->setMaxLength(ml);
479
480     emit maximumLengthChanged(ml);
481 }
482
483 /*!
484     \qmlproperty bool QtQuick2::TextInput::cursorVisible
485     Set to true when the TextInput shows a cursor.
486
487     This property is set and unset when the TextInput gets active focus, so that other
488     properties can be bound to whether the cursor is currently showing. As it
489     gets set and unset automatically, when you set the value yourself you must
490     keep in mind that your value may be overwritten.
491
492     It can be set directly in script, for example if a KeyProxy might
493     forward keys to it and you desire it to look active when this happens
494     (but without actually giving it active focus).
495
496     It should not be set directly on the element, like in the below QML,
497     as the specified value will be overridden an lost on focus changes.
498
499     \code
500     TextInput {
501         text: "Text"
502         cursorVisible: false
503     }
504     \endcode
505
506     In the above snippet the cursor will still become visible when the
507     TextInput gains active focus.
508 */
509 bool QQuickTextInput::isCursorVisible() const
510 {
511     Q_D(const QQuickTextInput);
512     return d->cursorVisible;
513 }
514
515 void QQuickTextInput::setCursorVisible(bool on)
516 {
517     Q_D(QQuickTextInput);
518     if (d->cursorVisible == on)
519         return;
520     d->cursorVisible = on;
521     d->control->setCursorBlinkPeriod(on ? qApp->styleHints()->cursorFlashTime() : 0);
522     QRect r = d->control->cursorRect();
523     if (d->control->inputMask().isEmpty())
524         updateRect(r);
525     else
526         updateRect();
527     emit cursorVisibleChanged(d->cursorVisible);
528 }
529
530 /*!
531     \qmlproperty int QtQuick2::TextInput::cursorPosition
532     The position of the cursor in the TextInput.
533 */
534 int QQuickTextInput::cursorPosition() const
535 {
536     Q_D(const QQuickTextInput);
537     return d->control->cursor();
538 }
539 void QQuickTextInput::setCursorPosition(int cp)
540 {
541     Q_D(QQuickTextInput);
542     if (cp < 0 || cp > d->control->text().length())
543         return;
544     d->control->moveCursor(cp);
545 }
546
547 /*!
548   Returns a Rect which encompasses the cursor, but which may be larger than is
549   required. Ignores custom cursor delegates.
550 */
551 QRect QQuickTextInput::cursorRectangle() const
552 {
553     Q_D(const QQuickTextInput);
554     QRect r = d->control->cursorRect();
555     // Scroll and make consistent with TextEdit
556     // QQuickLineControl inexplicably adds 1 to the height and horizontal padding
557     // for unicode direction markers.
558     r.adjust(5 - d->hscroll, 0, -4 - d->hscroll, -1);
559     return r;
560 }
561 /*!
562     \qmlproperty int QtQuick2::TextInput::selectionStart
563
564     The cursor position before the first character in the current selection.
565
566     This property is read-only. To change the selection, use select(start,end),
567     selectAll(), or selectWord().
568
569     \sa selectionEnd, cursorPosition, selectedText
570 */
571 int QQuickTextInput::selectionStart() const
572 {
573     Q_D(const QQuickTextInput);
574     return d->lastSelectionStart;
575 }
576 /*!
577     \qmlproperty int QtQuick2::TextInput::selectionEnd
578
579     The cursor position after the last 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 selectionStart, cursorPosition, selectedText
585 */
586 int QQuickTextInput::selectionEnd() const
587 {
588     Q_D(const QQuickTextInput);
589     return d->lastSelectionEnd;
590 }
591 /*!
592     \qmlmethod void QtQuick2::TextInput::select(int start, int end)
593
594     Causes the text from \a start to \a end to be selected.
595
596     If either start or end is out of range, the selection is not changed.
597
598     After calling this, selectionStart will become the lesser
599     and selectionEnd will become the greater (regardless of the order passed
600     to this method).
601
602     \sa selectionStart, selectionEnd
603 */
604 void QQuickTextInput::select(int start, int end)
605 {
606     Q_D(QQuickTextInput);
607     if (start < 0 || end < 0 || start > d->control->text().length() || end > d->control->text().length())
608         return;
609     d->control->setSelection(start, end-start);
610 }
611
612 /*!
613     \qmlproperty string QtQuick2::TextInput::selectedText
614
615     This read-only property provides the text currently selected in the
616     text input.
617
618     It is equivalent to the following snippet, but is faster and easier
619     to use.
620
621     \js
622     myTextInput.text.toString().substring(myTextInput.selectionStart,
623         myTextInput.selectionEnd);
624     \endjs
625 */
626 QString QQuickTextInput::selectedText() const
627 {
628     Q_D(const QQuickTextInput);
629     return d->control->selectedText();
630 }
631
632 /*!
633     \qmlproperty bool QtQuick2::TextInput::activeFocusOnPress
634
635     Whether the TextInput should gain active focus on a mouse press. By default this is
636     set to true.
637 */
638 bool QQuickTextInput::focusOnPress() const
639 {
640     Q_D(const QQuickTextInput);
641     return d->focusOnPress;
642 }
643
644 void QQuickTextInput::setFocusOnPress(bool b)
645 {
646     Q_D(QQuickTextInput);
647     if (d->focusOnPress == b)
648         return;
649
650     d->focusOnPress = b;
651
652     emit activeFocusOnPressChanged(d->focusOnPress);
653 }
654 /*!
655     \qmlproperty bool QtQuick2::TextInput::autoScroll
656
657     Whether the TextInput should scroll when the text is longer than the width. By default this is
658     set to true.
659 */
660 bool QQuickTextInput::autoScroll() const
661 {
662     Q_D(const QQuickTextInput);
663     return d->autoScroll;
664 }
665
666 void QQuickTextInput::setAutoScroll(bool b)
667 {
668     Q_D(QQuickTextInput);
669     if (d->autoScroll == b)
670         return;
671
672     d->autoScroll = b;
673     //We need to repaint so that the scrolling is taking into account.
674     updateSize(true);
675     updateCursorRectangle();
676     emit autoScrollChanged(d->autoScroll);
677 }
678
679 #ifndef QT_NO_VALIDATOR
680
681 /*!
682     \qmlclass IntValidator QIntValidator
683     \inqmlmodule QtQuick 2
684     \ingroup qml-basic-visual-elements
685
686     This element provides a validator for integer values.
687
688     IntValidator uses the \l {QLocale::setDefault()}{default locale} to interpret the number and
689     will accept locale specific digits, group separators, and positive and negative signs.  In
690     addition, IntValidator is always guaranteed to accept a number formatted according to the "C"
691     locale.
692 */
693 /*!
694     \qmlproperty int QtQuick2::IntValidator::top
695
696     This property holds the validator's highest acceptable value.
697     By default, this property's value is derived from the highest signed integer available (typically 2147483647).
698 */
699 /*!
700     \qmlproperty int QtQuick2::IntValidator::bottom
701
702     This property holds the validator's lowest acceptable value.
703     By default, this property's value is derived from the lowest signed integer available (typically -2147483647).
704 */
705
706 /*!
707     \qmlclass DoubleValidator QDoubleValidator
708     \inqmlmodule QtQuick 2
709     \ingroup qml-basic-visual-elements
710
711     This element provides a validator for non-integer numbers.
712 */
713
714 /*!
715     \qmlproperty real QtQuick2::DoubleValidator::top
716
717     This property holds the validator's maximum acceptable value.
718     By default, this property contains a value of infinity.
719 */
720 /*!
721     \qmlproperty real QtQuick2::DoubleValidator::bottom
722
723     This property holds the validator's minimum acceptable value.
724     By default, this property contains a value of -infinity.
725 */
726 /*!
727     \qmlproperty int QtQuick2::DoubleValidator::decimals
728
729     This property holds the validator's maximum number of digits after the decimal point.
730     By default, this property contains a value of 1000.
731 */
732 /*!
733     \qmlproperty enumeration QtQuick2::DoubleValidator::notation
734     This property holds the notation of how a string can describe a number.
735
736     The possible values for this property are:
737
738     \list
739     \o DoubleValidator.StandardNotation
740     \o DoubleValidator.ScientificNotation (default)
741     \endlist
742
743     If this property is set to DoubleValidator.ScientificNotation, the written number may have an exponent part (e.g. 1.5E-2).
744 */
745
746 /*!
747     \qmlclass RegExpValidator QRegExpValidator
748     \inqmlmodule QtQuick 2
749     \ingroup qml-basic-visual-elements
750
751     This element provides a validator, which counts as valid any string which
752     matches a specified regular expression.
753 */
754 /*!
755    \qmlproperty regExp QtQuick2::RegExpValidator::regExp
756
757    This property holds the regular expression used for validation.
758
759    Note that this property should be a regular expression in JS syntax, e.g /a/ for the regular expression
760    matching "a".
761
762    By default, this property contains a regular expression with the pattern .* that matches any string.
763 */
764
765 /*!
766     \qmlproperty Validator QtQuick2::TextInput::validator
767
768     Allows you to set a validator on the TextInput. When a validator is set
769     the TextInput will only accept input which leaves the text property in
770     an acceptable or intermediate state. The accepted signal will only be sent
771     if the text is in an acceptable state when enter is pressed.
772
773     Currently supported validators are IntValidator, DoubleValidator and
774     RegExpValidator. An example of using validators is shown below, which allows
775     input of integers between 11 and 31 into the text input:
776
777     \code
778     import QtQuick 1.0
779     TextInput{
780         validator: IntValidator{bottom: 11; top: 31;}
781         focus: true
782     }
783     \endcode
784
785     \sa acceptableInput, inputMask
786 */
787
788 QValidator* QQuickTextInput::validator() const
789 {
790     Q_D(const QQuickTextInput);
791     //###const cast isn't good, but needed for property system?
792     return const_cast<QValidator*>(d->control->validator());
793 }
794
795 void QQuickTextInput::setValidator(QValidator* v)
796 {
797     Q_D(QQuickTextInput);
798     if (d->control->validator() == v)
799         return;
800
801     d->control->setValidator(v);
802     if (!d->control->hasAcceptableInput()) {
803         d->oldValidity = false;
804         emit acceptableInputChanged();
805     }
806
807     emit validatorChanged();
808 }
809 #endif // QT_NO_VALIDATOR
810
811 /*!
812     \qmlproperty string QtQuick2::TextInput::inputMask
813
814     Allows you to set an input mask on the TextInput, restricting the allowable
815     text inputs. See QLineEdit::inputMask for further details, as the exact
816     same mask strings are used by TextInput.
817
818     \sa acceptableInput, validator
819 */
820 QString QQuickTextInput::inputMask() const
821 {
822     Q_D(const QQuickTextInput);
823     return d->control->inputMask();
824 }
825
826 void QQuickTextInput::setInputMask(const QString &im)
827 {
828     Q_D(QQuickTextInput);
829     if (d->control->inputMask() == im)
830         return;
831
832     d->control->setInputMask(im);
833     emit inputMaskChanged(d->control->inputMask());
834 }
835
836 /*!
837     \qmlproperty bool QtQuick2::TextInput::acceptableInput
838
839     This property is always true unless a validator or input mask has been set.
840     If a validator or input mask has been set, this property will only be true
841     if the current text is acceptable to the validator or input mask as a final
842     string (not as an intermediate string).
843 */
844 bool QQuickTextInput::hasAcceptableInput() const
845 {
846     Q_D(const QQuickTextInput);
847     return d->control->hasAcceptableInput();
848 }
849
850 /*!
851     \qmlsignal QtQuick2::TextInput::onAccepted()
852
853     This handler is called when the Return or Enter key is pressed.
854     Note that if there is a \l validator or \l inputMask set on the text
855     input, the handler will only be emitted if the input is in an acceptable
856     state.
857 */
858
859 void QQuickTextInputPrivate::updateInputMethodHints()
860 {
861     Q_Q(QQuickTextInput);
862     Qt::InputMethodHints hints = inputMethodHints;
863     uint echo = control->echoMode();
864     if (echo == QQuickTextInput::Password || echo == QQuickTextInput::NoEcho)
865         hints |= Qt::ImhHiddenText;
866     else if (echo == QQuickTextInput::PasswordEchoOnEdit)
867         hints &= ~Qt::ImhHiddenText;
868     if (echo != QQuickTextInput::Normal)
869         hints |= (Qt::ImhNoAutoUppercase | Qt::ImhNoPredictiveText);
870     q->setInputMethodHints(hints);
871 }
872 /*!
873     \qmlproperty enumeration QtQuick2::TextInput::echoMode
874
875     Specifies how the text should be displayed in the TextInput.
876     \list
877     \o TextInput.Normal - Displays the text as it is. (Default)
878     \o TextInput.Password - Displays asterisks instead of characters.
879     \o TextInput.NoEcho - Displays nothing.
880     \o TextInput.PasswordEchoOnEdit - Displays characters as they are entered
881     while editing, otherwise displays asterisks.
882     \endlist
883 */
884 QQuickTextInput::EchoMode QQuickTextInput::echoMode() const
885 {
886     Q_D(const QQuickTextInput);
887     return (QQuickTextInput::EchoMode)d->control->echoMode();
888 }
889
890 void QQuickTextInput::setEchoMode(QQuickTextInput::EchoMode echo)
891 {
892     Q_D(QQuickTextInput);
893     if (echoMode() == echo)
894         return;
895     d->control->setEchoMode((QQuickLineControl::EchoMode)echo);
896     d->updateInputMethodHints();
897     q_textChanged();
898     emit echoModeChanged(echoMode());
899 }
900
901 Qt::InputMethodHints QQuickTextInput::imHints() const
902 {
903     Q_D(const QQuickTextInput);
904     return d->inputMethodHints;
905 }
906
907 void QQuickTextInput::setIMHints(Qt::InputMethodHints hints)
908 {
909     Q_D(QQuickTextInput);
910     if (d->inputMethodHints == hints)
911         return;
912     d->inputMethodHints = hints;
913     d->updateInputMethodHints();
914 }
915
916 /*!
917     \qmlproperty Component QtQuick2::TextInput::cursorDelegate
918     The delegate for the cursor in the TextInput.
919
920     If you set a cursorDelegate for a TextInput, this delegate will be used for
921     drawing the cursor instead of the standard cursor. An instance of the
922     delegate will be created and managed by the TextInput when a cursor is
923     needed, and the x property of delegate instance will be set so as
924     to be one pixel before the top left of the current character.
925
926     Note that the root item of the delegate component must be a QDeclarativeItem or
927     QDeclarativeItem derived item.
928 */
929 QDeclarativeComponent* QQuickTextInput::cursorDelegate() const
930 {
931     Q_D(const QQuickTextInput);
932     return d->cursorComponent;
933 }
934
935 void QQuickTextInput::setCursorDelegate(QDeclarativeComponent* c)
936 {
937     Q_D(QQuickTextInput);
938     if (d->cursorComponent == c)
939         return;
940
941     d->cursorComponent = c;
942     if (!c) {
943         //note that the components are owned by something else
944         delete d->cursorItem;
945     } else {
946         d->startCreatingCursor();
947     }
948
949     emit cursorDelegateChanged();
950 }
951
952 void QQuickTextInputPrivate::startCreatingCursor()
953 {
954     Q_Q(QQuickTextInput);
955     if (cursorComponent->isReady()) {
956         q->createCursor();
957     } else if (cursorComponent->isLoading()) {
958         q->connect(cursorComponent, SIGNAL(statusChanged(int)),
959                 q, SLOT(createCursor()));
960     } else { // isError
961         qmlInfo(q, cursorComponent->errors()) << QQuickTextInput::tr("Could not load cursor delegate");
962     }
963 }
964
965 void QQuickTextInput::createCursor()
966 {
967     Q_D(QQuickTextInput);
968     if (d->cursorComponent->isError()) {
969         qmlInfo(this, d->cursorComponent->errors()) << tr("Could not load cursor delegate");
970         return;
971     }
972
973     if (!d->cursorComponent->isReady())
974         return;
975
976     if (d->cursorItem)
977         delete d->cursorItem;
978     QDeclarativeContext *creationContext = d->cursorComponent->creationContext();
979     QObject *object = d->cursorComponent->create(creationContext ? creationContext : qmlContext(this));
980     d->cursorItem = qobject_cast<QQuickItem*>(object);
981     if (!d->cursorItem) {
982         delete object;
983         qmlInfo(this, d->cursorComponent->errors()) << tr("Could not instantiate cursor delegate");
984         return;
985     }
986
987     QDeclarative_setParent_noEvent(d->cursorItem, this);
988     d->cursorItem->setParentItem(this);
989     d->cursorItem->setX(d->control->cursorToX());
990     d->cursorItem->setHeight(d->control->height()-1); // -1 to counter QQuickLineControl's +1 which is not consistent with Text.
991 }
992
993 /*!
994     \qmlmethod rect QtQuick2::TextInput::positionToRectangle(int pos)
995
996     This function takes a character position and returns the rectangle that the
997     cursor would occupy, if it was placed at that character position.
998
999     This is similar to setting the cursorPosition, and then querying the cursor
1000     rectangle, but the cursorPosition is not changed.
1001 */
1002 QRectF QQuickTextInput::positionToRectangle(int pos) const
1003 {
1004     Q_D(const QQuickTextInput);
1005     if (pos > d->control->cursorPosition())
1006         pos += d->control->preeditAreaText().length();
1007     return QRectF(d->control->cursorToX(pos)-d->hscroll,
1008         0.0,
1009         d->control->cursorWidth(),
1010         cursorRectangle().height());
1011 }
1012
1013 /*!
1014     \qmlmethod int QtQuick2::TextInput::positionAt(int x, CursorPosition position = CursorBetweenCharacters)
1015
1016     This function returns the character position at
1017     x pixels from the left of the textInput. Position 0 is before the
1018     first character, position 1 is after the first character but before the second,
1019     and so on until position text.length, which is after all characters.
1020
1021     This means that for all x values before the first character this function returns 0,
1022     and for all x values after the last character this function returns text.length.
1023
1024     The cursor position type specifies how the cursor position should be resolved.
1025
1026     \list
1027     \o TextInput.CursorBetweenCharacters - Returns the position between characters that is nearest x.
1028     \o TextInput.CursorOnCharacter - Returns the position before the character that is nearest x.
1029     \endlist
1030 */
1031 int QQuickTextInput::positionAt(int x) const
1032 {
1033     return positionAt(x, CursorBetweenCharacters);
1034 }
1035
1036 int QQuickTextInput::positionAt(int x, CursorPosition position) const
1037 {
1038     Q_D(const QQuickTextInput);
1039     int pos = d->control->xToPos(x + d->hscroll, QTextLine::CursorPosition(position));
1040     const int cursor = d->control->cursor();
1041     if (pos > cursor) {
1042         const int preeditLength = d->control->preeditAreaText().length();
1043         pos = pos > cursor + preeditLength
1044                 ? pos - preeditLength
1045                 : cursor;
1046     }
1047     return pos;
1048 }
1049
1050 void QQuickTextInput::keyPressEvent(QKeyEvent* ev)
1051 {
1052     Q_D(QQuickTextInput);
1053     // Don't allow MacOSX up/down support, and we don't allow a completer.
1054     bool ignore = (ev->key() == Qt::Key_Up || ev->key() == Qt::Key_Down) && ev->modifiers() == Qt::NoModifier;
1055     if (!ignore && (d->lastSelectionStart == d->lastSelectionEnd) && (ev->key() == Qt::Key_Right || ev->key() == Qt::Key_Left)) {
1056         // Ignore when moving off the end unless there is a selection,
1057         // because then moving will do something (deselect).
1058         int cursorPosition = d->control->cursor();
1059         if (cursorPosition == 0)
1060             ignore = ev->key() == (d->control->layoutDirection() == Qt::LeftToRight ? Qt::Key_Left : Qt::Key_Right);
1061         if (cursorPosition == d->control->text().length())
1062             ignore = ev->key() == (d->control->layoutDirection() == Qt::LeftToRight ? Qt::Key_Right : Qt::Key_Left);
1063     }
1064     if (ignore) {
1065         ev->ignore();
1066     } else {
1067         d->control->processKeyEvent(ev);
1068     }
1069     if (!ev->isAccepted())
1070         QQuickImplicitSizeItem::keyPressEvent(ev);
1071 }
1072
1073 void QQuickTextInput::inputMethodEvent(QInputMethodEvent *ev)
1074 {
1075     Q_D(QQuickTextInput);
1076     const bool wasComposing = d->control->preeditAreaText().length() > 0;
1077     if (d->control->isReadOnly()) {
1078         ev->ignore();
1079     } else {
1080         d->control->processInputMethodEvent(ev);
1081     }
1082     if (!ev->isAccepted())
1083         QQuickImplicitSizeItem::inputMethodEvent(ev);
1084
1085     if (wasComposing != (d->control->preeditAreaText().length() > 0))
1086         emit inputMethodComposingChanged();
1087 }
1088
1089 void QQuickTextInput::mouseDoubleClickEvent(QMouseEvent *event)
1090 {
1091     Q_D(QQuickTextInput);
1092
1093     if (d->selectByMouse && event->button() == Qt::LeftButton) {
1094         d->control->commitPreedit();
1095         int cursor = d->xToPos(event->localPos().x());
1096         d->control->selectWordAtPos(cursor);
1097         event->setAccepted(true);
1098         if (!d->hasPendingTripleClick()) {
1099             d->tripleClickStartPoint = event->localPos().toPoint();
1100             d->tripleClickTimer.start();
1101         }
1102     } else {
1103         if (d->sendMouseEventToInputContext(event))
1104             return;
1105         QQuickImplicitSizeItem::mouseDoubleClickEvent(event);
1106     }
1107 }
1108
1109 void QQuickTextInput::mousePressEvent(QMouseEvent *event)
1110 {
1111     Q_D(QQuickTextInput);
1112
1113     d->pressPos = event->localPos();
1114
1115     if (d->focusOnPress) {
1116         bool hadActiveFocus = hasActiveFocus();
1117         forceActiveFocus();
1118         // re-open input panel on press if already focused
1119         if (hasActiveFocus() && hadActiveFocus && !isReadOnly())
1120             openSoftwareInputPanel();
1121     }
1122     if (d->selectByMouse) {
1123         setKeepMouseGrab(false);
1124         d->selectPressed = true;
1125         QPoint distanceVector = d->pressPos.toPoint() - d->tripleClickStartPoint;
1126         if (d->hasPendingTripleClick()
1127             && distanceVector.manhattanLength() < qApp->styleHints()->startDragDistance()) {
1128             event->setAccepted(true);
1129             selectAll();
1130             return;
1131         }
1132     }
1133
1134     if (d->sendMouseEventToInputContext(event))
1135         return;
1136
1137     bool mark = (event->modifiers() & Qt::ShiftModifier) && d->selectByMouse;
1138     int cursor = d->xToPos(event->localPos().x());
1139     d->control->moveCursor(cursor, mark);
1140     event->setAccepted(true);
1141 }
1142
1143 void QQuickTextInput::mouseMoveEvent(QMouseEvent *event)
1144 {
1145     Q_D(QQuickTextInput);
1146
1147     if (d->selectPressed) {
1148         if (qAbs(int(event->localPos().x() - d->pressPos.x())) > qApp->styleHints()->startDragDistance())
1149             setKeepMouseGrab(true);
1150
1151         if (d->control->composeMode()) {
1152             // start selection
1153             int startPos = d->xToPos(d->pressPos.x());
1154             int currentPos = d->xToPos(event->localPos().x());
1155             if (startPos != currentPos)
1156                 d->control->setSelection(startPos, currentPos - startPos);
1157         } else {
1158             moveCursorSelection(d->xToPos(event->localPos().x()), d->mouseSelectionMode);
1159         }
1160         event->setAccepted(true);
1161     } else {
1162         QQuickImplicitSizeItem::mouseMoveEvent(event);
1163     }
1164 }
1165
1166 void QQuickTextInput::mouseReleaseEvent(QMouseEvent *event)
1167 {
1168     Q_D(QQuickTextInput);
1169     if (d->sendMouseEventToInputContext(event))
1170         return;
1171     if (d->selectPressed) {
1172         d->selectPressed = false;
1173         setKeepMouseGrab(false);
1174     }
1175     d->control->processEvent(event);
1176     if (!event->isAccepted())
1177         QQuickImplicitSizeItem::mouseReleaseEvent(event);
1178 }
1179
1180 bool QQuickTextInputPrivate::sendMouseEventToInputContext(QMouseEvent *event)
1181 {
1182 #if !defined QT_NO_IM
1183     if (control->composeMode()) {
1184         int tmp_cursor = xToPos(event->localPos().x());
1185         int mousePos = tmp_cursor - control->cursor();
1186         if (mousePos >= 0 && mousePos <= control->preeditAreaText().length()) {
1187             if (event->type() == QEvent::MouseButtonRelease) {
1188                 qApp->inputPanel()->invokeAction(QInputPanel::Click, mousePos);
1189             }
1190             return true;
1191         }
1192     }
1193 #else
1194     Q_UNUSED(event);
1195     Q_UNUSED(eventType)
1196 #endif
1197
1198     return false;
1199 }
1200
1201 void QQuickTextInput::mouseUngrabEvent()
1202 {
1203     Q_D(QQuickTextInput);
1204     d->selectPressed = false;
1205     setKeepMouseGrab(false);
1206 }
1207
1208 bool QQuickTextInput::event(QEvent* ev)
1209 {
1210     Q_D(QQuickTextInput);
1211     //Anything we don't deal with ourselves, pass to the control
1212     bool handled = false;
1213     switch (ev->type()) {
1214         case QEvent::KeyPress:
1215         case QEvent::KeyRelease://###Should the control be doing anything with release?
1216         case QEvent::InputMethod:
1217         case QEvent::MouseButtonPress:
1218         case QEvent::MouseMove:
1219         case QEvent::MouseButtonRelease:
1220         case QEvent::MouseButtonDblClick:
1221             break;
1222         default:
1223             handled = d->control->processEvent(ev);
1224     }
1225     if (!handled)
1226         handled = QQuickImplicitSizeItem::event(ev);
1227     return handled;
1228 }
1229
1230 void QQuickTextInput::geometryChanged(const QRectF &newGeometry,
1231                                   const QRectF &oldGeometry)
1232 {
1233     if (newGeometry.width() != oldGeometry.width()) {
1234         updateSize();
1235         updateCursorRectangle();
1236     }
1237     QQuickImplicitSizeItem::geometryChanged(newGeometry, oldGeometry);
1238 }
1239
1240 int QQuickTextInputPrivate::calculateTextWidth()
1241 {
1242     return qRound(control->naturalTextWidth());
1243 }
1244
1245 void QQuickTextInputPrivate::updateHorizontalScroll()
1246 {
1247     Q_Q(QQuickTextInput);
1248     const int preeditLength = control->preeditAreaText().length();
1249     const int width = q->width();
1250     int widthUsed = calculateTextWidth();
1251
1252     if (!autoScroll || widthUsed <=  width) {
1253         QQuickTextInput::HAlignment effectiveHAlign = q->effectiveHAlign();
1254         // text fits in br; use hscroll for alignment
1255         switch (effectiveHAlign & ~(Qt::AlignAbsolute|Qt::AlignVertical_Mask)) {
1256         case Qt::AlignRight:
1257             hscroll = widthUsed - width;
1258             break;
1259         case Qt::AlignHCenter:
1260             hscroll = (widthUsed - width) / 2;
1261             break;
1262         default:
1263             // Left
1264             hscroll = 0;
1265             break;
1266         }
1267     } else {
1268         int cix = qRound(control->cursorToX(control->cursor() + preeditLength));
1269         if (cix - hscroll >= width) {
1270             // text doesn't fit, cursor is to the right of br (scroll right)
1271             hscroll = cix - width;
1272         } else if (cix - hscroll < 0 && hscroll < widthUsed) {
1273             // text doesn't fit, cursor is to the left of br (scroll left)
1274             hscroll = cix;
1275         } else if (widthUsed - hscroll < width) {
1276             // text doesn't fit, text document is to the left of br; align
1277             // right
1278             hscroll = widthUsed - width;
1279         }
1280         if (preeditLength > 0) {
1281             // check to ensure long pre-edit text doesn't push the cursor
1282             // off to the left
1283              cix = qRound(control->cursorToX(
1284                      control->cursor() + qMax(0, control->preeditCursor() - 1)));
1285              if (cix < hscroll)
1286                  hscroll = cix;
1287         }
1288     }
1289 }
1290
1291 QSGNode *QQuickTextInput::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
1292 {
1293     Q_UNUSED(data);
1294     Q_D(QQuickTextInput);
1295
1296     QQuickTextNode *node = static_cast<QQuickTextNode *>(oldNode);
1297     if (node == 0)
1298         node = new QQuickTextNode(QQuickItemPrivate::get(this)->sceneGraphContext());
1299     d->textNode = node;
1300
1301     if (!d->textLayoutDirty) {
1302         QSGSimpleRectNode *cursorNode = node->cursorNode();
1303         if (cursorNode != 0 && !isReadOnly()) {
1304             cursorNode->setRect(cursorRectangle());
1305
1306             if (!d->cursorVisible
1307                     || (!d->control->cursorBlinkStatus() && d->control->cursorBlinkPeriod() > 0)) {
1308                 d->hideCursor();
1309             } else {
1310                 d->showCursor();
1311             }
1312         }
1313     } else {
1314         node->deleteContent();
1315         node->setMatrix(QMatrix4x4());
1316
1317         QPoint offset = QPoint(0,0);
1318         QFontMetrics fm = QFontMetrics(d->font);
1319         QRect br(boundingRect().toRect());
1320         if (d->autoScroll) {
1321             // the y offset is there to keep the baseline constant in case we have script changes in the text.
1322             offset = br.topLeft() - QPoint(d->hscroll, d->control->ascent() - fm.ascent());
1323         } else {
1324             offset = QPoint(d->hscroll, 0);
1325         }
1326
1327         QTextLayout *textLayout = d->control->textLayout();
1328         if (!textLayout->text().isEmpty()) {
1329             node->addTextLayout(offset, textLayout, d->color,
1330                                 QQuickText::Normal, QColor(),
1331                                 d->selectionColor, d->selectedTextColor,
1332                                 d->control->selectionStart(),
1333                                 d->control->selectionEnd() - 1); // selectionEnd() returns first char after
1334                                                                  // selection
1335         }
1336
1337         if (!isReadOnly() && d->cursorItem == 0) {
1338             node->setCursor(cursorRectangle(), d->color);
1339             if (!d->cursorVisible
1340                     || (!d->control->cursorBlinkStatus() && d->control->cursorBlinkPeriod() > 0)) {
1341                 d->hideCursor();
1342             } else {
1343                 d->showCursor();
1344             }
1345         }
1346
1347         d->textLayoutDirty = false;
1348     }
1349
1350     return node;
1351 }
1352
1353 QVariant QQuickTextInput::inputMethodQuery(Qt::InputMethodQuery property) const
1354 {
1355     Q_D(const QQuickTextInput);
1356     switch (property) {
1357     case Qt::ImEnabled:
1358         return QVariant((bool)(flags() & ItemAcceptsInputMethod));
1359     case Qt::ImHints:
1360         return QVariant((int)inputMethodHints());
1361     case Qt::ImCursorRectangle:
1362         return cursorRectangle();
1363     case Qt::ImFont:
1364         return font();
1365     case Qt::ImCursorPosition:
1366         return QVariant(d->control->cursor());
1367     case Qt::ImSurroundingText:
1368         if (d->control->echoMode() == QQuickLineControl::PasswordEchoOnEdit
1369             && !d->control->passwordEchoEditing()) {
1370             return QVariant(displayText());
1371         } else {
1372             return QVariant(d->control->realText());
1373         }
1374     case Qt::ImCurrentSelection:
1375         return QVariant(selectedText());
1376     case Qt::ImMaximumTextLength:
1377         return QVariant(maxLength());
1378     case Qt::ImAnchorPosition:
1379         if (d->control->selectionStart() == d->control->selectionEnd())
1380             return QVariant(d->control->cursor());
1381         else if (d->control->selectionStart() == d->control->cursor())
1382             return QVariant(d->control->selectionEnd());
1383         else
1384             return QVariant(d->control->selectionStart());
1385     default:
1386         return QVariant();
1387     }
1388 }
1389
1390 /*!
1391     \qmlmethod void QtQuick2::TextInput::deselect()
1392
1393     Removes active text selection.
1394 */
1395 void QQuickTextInput::deselect()
1396 {
1397     Q_D(QQuickTextInput);
1398     d->control->deselect();
1399 }
1400
1401 /*!
1402     \qmlmethod void QtQuick2::TextInput::selectAll()
1403
1404     Causes all text to be selected.
1405 */
1406 void QQuickTextInput::selectAll()
1407 {
1408     Q_D(QQuickTextInput);
1409     d->control->setSelection(0, d->control->text().length());
1410 }
1411
1412 /*!
1413     \qmlmethod void QtQuick2::TextInput::isRightToLeft(int start, int end)
1414
1415     Returns true if the natural reading direction of the editor text
1416     found between positions \a start and \a end is right to left.
1417 */
1418 bool QQuickTextInput::isRightToLeft(int start, int end)
1419 {
1420     Q_D(QQuickTextInput);
1421     if (start > end) {
1422         qmlInfo(this) << "isRightToLeft(start, end) called with the end property being smaller than the start.";
1423         return false;
1424     } else {
1425         return d->control->text().mid(start, end - start).isRightToLeft();
1426     }
1427 }
1428
1429 #ifndef QT_NO_CLIPBOARD
1430 /*!
1431     \qmlmethod QtQuick2::TextInput::cut()
1432
1433     Moves the currently selected text to the system clipboard.
1434 */
1435 void QQuickTextInput::cut()
1436 {
1437     Q_D(QQuickTextInput);
1438     d->control->copy();
1439     d->control->del();
1440 }
1441
1442 /*!
1443     \qmlmethod QtQuick2::TextInput::copy()
1444
1445     Copies the currently selected text to the system clipboard.
1446 */
1447 void QQuickTextInput::copy()
1448 {
1449     Q_D(QQuickTextInput);
1450     d->control->copy();
1451 }
1452
1453 /*!
1454     \qmlmethod QtQuick2::TextInput::paste()
1455
1456     Replaces the currently selected text by the contents of the system clipboard.
1457 */
1458 void QQuickTextInput::paste()
1459 {
1460     Q_D(QQuickTextInput);
1461     if (!d->control->isReadOnly())
1462         d->control->paste();
1463 }
1464 #endif // QT_NO_CLIPBOARD
1465
1466 /*!
1467     \qmlmethod void QtQuick2::TextInput::selectWord()
1468
1469     Causes the word closest to the current cursor position to be selected.
1470 */
1471 void QQuickTextInput::selectWord()
1472 {
1473     Q_D(QQuickTextInput);
1474     d->control->selectWordAtPos(d->control->cursor());
1475 }
1476
1477 /*!
1478     \qmlproperty bool QtQuick2::TextInput::smooth
1479
1480     This property holds whether the text is smoothly scaled or transformed.
1481
1482     Smooth filtering gives better visual quality, but is slower.  If
1483     the item is displayed at its natural size, this property has no visual or
1484     performance effect.
1485
1486     \note Generally scaling artifacts are only visible if the item is stationary on
1487     the screen.  A common pattern when animating an item is to disable smooth
1488     filtering at the beginning of the animation and reenable it at the conclusion.
1489 */
1490
1491 /*!
1492    \qmlproperty string QtQuick2::TextInput::passwordCharacter
1493
1494    This is the character displayed when echoMode is set to Password or
1495    PasswordEchoOnEdit. By default it is an asterisk.
1496
1497    If this property is set to a string with more than one character,
1498    the first character is used. If the string is empty, the value
1499    is ignored and the property is not set.
1500 */
1501 QString QQuickTextInput::passwordCharacter() const
1502 {
1503     Q_D(const QQuickTextInput);
1504     return QString(d->control->passwordCharacter());
1505 }
1506
1507 void QQuickTextInput::setPasswordCharacter(const QString &str)
1508 {
1509     Q_D(QQuickTextInput);
1510     if (str.length() < 1)
1511         return;
1512     d->control->setPasswordCharacter(str.constData()[0]);
1513     EchoMode echoMode_ = echoMode();
1514     if (echoMode_ == Password || echoMode_ == PasswordEchoOnEdit) {
1515         updateSize();
1516     }
1517     emit passwordCharacterChanged();
1518 }
1519
1520 /*!
1521    \qmlproperty string QtQuick2::TextInput::displayText
1522
1523    This is the text displayed in the TextInput.
1524
1525    If \l echoMode is set to TextInput::Normal, this holds the
1526    same value as the TextInput::text property. Otherwise,
1527    this property holds the text visible to the user, while
1528    the \l text property holds the actual entered text.
1529 */
1530 QString QQuickTextInput::displayText() const
1531 {
1532     Q_D(const QQuickTextInput);
1533     return d->control->displayText();
1534 }
1535
1536 /*!
1537     \qmlproperty bool QtQuick2::TextInput::selectByMouse
1538
1539     Defaults to false.
1540
1541     If true, the user can use the mouse to select text in some
1542     platform-specific way. Note that for some platforms this may
1543     not be an appropriate interaction (eg. may conflict with how
1544     the text needs to behave inside a Flickable.
1545 */
1546 bool QQuickTextInput::selectByMouse() const
1547 {
1548     Q_D(const QQuickTextInput);
1549     return d->selectByMouse;
1550 }
1551
1552 void QQuickTextInput::setSelectByMouse(bool on)
1553 {
1554     Q_D(QQuickTextInput);
1555     if (d->selectByMouse != on) {
1556         d->selectByMouse = on;
1557         emit selectByMouseChanged(on);
1558     }
1559 }
1560
1561 /*!
1562     \qmlproperty enum QtQuick2::TextInput::mouseSelectionMode
1563
1564     Specifies how text should be selected using a mouse.
1565
1566     \list
1567     \o TextInput.SelectCharacters - The selection is updated with individual characters. (Default)
1568     \o TextInput.SelectWords - The selection is updated with whole words.
1569     \endlist
1570
1571     This property only applies when \l selectByMouse is true.
1572 */
1573
1574 QQuickTextInput::SelectionMode QQuickTextInput::mouseSelectionMode() const
1575 {
1576     Q_D(const QQuickTextInput);
1577     return d->mouseSelectionMode;
1578 }
1579
1580 void QQuickTextInput::setMouseSelectionMode(SelectionMode mode)
1581 {
1582     Q_D(QQuickTextInput);
1583     if (d->mouseSelectionMode != mode) {
1584         d->mouseSelectionMode = mode;
1585         emit mouseSelectionModeChanged(mode);
1586     }
1587 }
1588
1589 /*!
1590     \qmlproperty bool QtQuick2::TextInput::canPaste
1591
1592     Returns true if the TextInput is writable and the content of the clipboard is
1593     suitable for pasting into the TextEdit.
1594 */
1595 bool QQuickTextInput::canPaste() const
1596 {
1597     Q_D(const QQuickTextInput);
1598     return d->canPaste;
1599 }
1600
1601 void QQuickTextInput::moveCursorSelection(int position)
1602 {
1603     Q_D(QQuickTextInput);
1604     d->control->moveCursor(position, true);
1605 }
1606
1607 /*!
1608     \qmlmethod void QtQuick2::TextInput::moveCursorSelection(int position, SelectionMode mode = TextInput.SelectCharacters)
1609
1610     Moves the cursor to \a position and updates the selection according to the optional \a mode
1611     parameter.  (To only move the cursor, set the \l cursorPosition property.)
1612
1613     When this method is called it additionally sets either the
1614     selectionStart or the selectionEnd (whichever was at the previous cursor position)
1615     to the specified position. This allows you to easily extend and contract the selected
1616     text range.
1617
1618     The selection mode specifies whether the selection is updated on a per character or a per word
1619     basis.  If not specified the selection mode will default to TextInput.SelectCharacters.
1620
1621     \list
1622     \o TextEdit.SelectCharacters - Sets either the selectionStart or selectionEnd (whichever was at
1623     the previous cursor position) to the specified position.
1624     \o TextEdit.SelectWords - Sets the selectionStart and selectionEnd to include all
1625     words between the specified position and the previous cursor position.  Words partially in the
1626     range are included.
1627     \endlist
1628
1629     For example, take this sequence of calls:
1630
1631     \code
1632         cursorPosition = 5
1633         moveCursorSelection(9, TextInput.SelectCharacters)
1634         moveCursorSelection(7, TextInput.SelectCharacters)
1635     \endcode
1636
1637     This moves the cursor to position 5, extend the selection end from 5 to 9
1638     and then retract the selection end from 9 to 7, leaving the text from position 5 to 7
1639     selected (the 6th and 7th characters).
1640
1641     The same sequence with TextInput.SelectWords will extend the selection start to a word boundary
1642     before or on position 5 and extend the selection end to a word boundary on or past position 9.
1643 */
1644 void QQuickTextInput::moveCursorSelection(int pos, SelectionMode mode)
1645 {
1646     Q_D(QQuickTextInput);
1647
1648     if (mode == SelectCharacters) {
1649         d->control->moveCursor(pos, true);
1650     } else if (pos != d->control->cursor()){
1651         const int cursor = d->control->cursor();
1652         int anchor;
1653         if (!d->control->hasSelectedText())
1654             anchor = d->control->cursor();
1655         else if (d->control->selectionStart() == d->control->cursor())
1656             anchor = d->control->selectionEnd();
1657         else
1658             anchor = d->control->selectionStart();
1659
1660         if (anchor < pos || (anchor == pos && cursor < pos)) {
1661             const QString text = d->control->text();
1662             QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
1663             finder.setPosition(anchor);
1664
1665             const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
1666             if (anchor < text.length() && (!(reasons & QTextBoundaryFinder::StartWord)
1667                     || ((reasons & QTextBoundaryFinder::EndWord) && anchor > cursor))) {
1668                 finder.toPreviousBoundary();
1669             }
1670             anchor = finder.position() != -1 ? finder.position() : 0;
1671
1672             finder.setPosition(pos);
1673             if (pos > 0 && !finder.boundaryReasons())
1674                 finder.toNextBoundary();
1675             const int cursor = finder.position() != -1 ? finder.position() : text.length();
1676
1677             d->control->setSelection(anchor, cursor - anchor);
1678         } else if (anchor > pos || (anchor == pos && cursor > pos)) {
1679             const QString text = d->control->text();
1680             QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
1681             finder.setPosition(anchor);
1682
1683             const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
1684             if (anchor > 0 && (!(reasons & QTextBoundaryFinder::EndWord)
1685                     || ((reasons & QTextBoundaryFinder::StartWord) && anchor < cursor))) {
1686                 finder.toNextBoundary();
1687             }
1688
1689             anchor = finder.position() != -1 ? finder.position() : text.length();
1690
1691             finder.setPosition(pos);
1692             if (pos < text.length() && !finder.boundaryReasons())
1693                  finder.toPreviousBoundary();
1694             const int cursor = finder.position() != -1 ? finder.position() : 0;
1695
1696             d->control->setSelection(anchor, cursor - anchor);
1697         }
1698     }
1699 }
1700
1701 /*!
1702     \qmlmethod void QtQuick2::TextInput::openSoftwareInputPanel()
1703
1704     Opens software input panels like virtual keyboards for typing, useful for
1705     customizing when you want the input keyboard to be shown and hidden in
1706     your application.
1707
1708     By default the opening of input panels follows the platform style. Input panels are
1709     always closed if no editor has active focus.
1710
1711     You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
1712     and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
1713     the behavior you want.
1714
1715     Only relevant on platforms, which provide virtual keyboards.
1716
1717     \qml
1718         import QtQuick 1.0
1719         TextInput {
1720             id: textInput
1721             text: "Hello world!"
1722             activeFocusOnPress: false
1723             MouseArea {
1724                 anchors.fill: parent
1725                 onClicked: {
1726                     if (!textInput.activeFocus) {
1727                         textInput.forceActiveFocus()
1728                         textInput.openSoftwareInputPanel();
1729                     } else {
1730                         textInput.focus = false;
1731                     }
1732                 }
1733                 onPressAndHold: textInput.closeSoftwareInputPanel();
1734             }
1735         }
1736     \endqml
1737 */
1738 void QQuickTextInput::openSoftwareInputPanel()
1739 {
1740     if (qGuiApp)
1741         qGuiApp->inputPanel()->show();
1742 }
1743
1744 /*!
1745     \qmlmethod void QtQuick2::TextInput::closeSoftwareInputPanel()
1746
1747     Closes a software input panel like a virtual keyboard shown on the screen, useful
1748     for customizing when you want the input keyboard to be shown and hidden in
1749     your application.
1750
1751     By default the opening of input panels follows the platform style. Input panels are
1752     always closed if no editor has active focus.
1753
1754     You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
1755     and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
1756     the behavior you want.
1757
1758     Only relevant on platforms, which provide virtual keyboards.
1759
1760     \qml
1761         import QtQuick 1.0
1762         TextInput {
1763             id: textInput
1764             text: "Hello world!"
1765             activeFocusOnPress: false
1766             MouseArea {
1767                 anchors.fill: parent
1768                 onClicked: {
1769                     if (!textInput.activeFocus) {
1770                         textInput.forceActiveFocus();
1771                         textInput.openSoftwareInputPanel();
1772                     } else {
1773                         textInput.focus = false;
1774                     }
1775                 }
1776                 onPressAndHold: textInput.closeSoftwareInputPanel();
1777             }
1778         }
1779     \endqml
1780 */
1781 void QQuickTextInput::closeSoftwareInputPanel()
1782 {
1783     if (qGuiApp)
1784         qGuiApp->inputPanel()->hide();
1785 }
1786
1787 void QQuickTextInput::focusInEvent(QFocusEvent *event)
1788 {
1789     Q_D(const QQuickTextInput);
1790     if (d->focusOnPress && !isReadOnly())
1791         openSoftwareInputPanel();
1792     QQuickImplicitSizeItem::focusInEvent(event);
1793 }
1794
1795 void QQuickTextInput::itemChange(ItemChange change, const ItemChangeData &value)
1796 {
1797     Q_D(QQuickTextInput);
1798     if (change == ItemActiveFocusHasChanged) {
1799         bool hasFocus = value.boolValue;
1800         d->focused = hasFocus;
1801         setCursorVisible(hasFocus); // ### refactor:  && d->canvas && d->canvas->hasFocus()
1802         if (echoMode() == QQuickTextInput::PasswordEchoOnEdit && !hasFocus)
1803             d->control->updatePasswordEchoEditing(false);//QQuickLineControl sets it on key events, but doesn't deal with focus events
1804         if (!hasFocus)
1805             d->control->deselect();
1806     }
1807     QQuickItem::itemChange(change, value);
1808 }
1809
1810 /*!
1811     \qmlproperty bool QtQuick2::TextInput::inputMethodComposing
1812
1813
1814     This property holds whether the TextInput has partial text input from an
1815     input method.
1816
1817     While it is composing an input method may rely on mouse or key events from
1818     the TextInput to edit or commit the partial text.  This property can be
1819     used to determine when to disable events handlers that may interfere with
1820     the correct operation of an input method.
1821 */
1822 bool QQuickTextInput::isInputMethodComposing() const
1823 {
1824     Q_D(const QQuickTextInput);
1825     return d->control->preeditAreaText().length() > 0;
1826 }
1827
1828 void QQuickTextInputPrivate::init()
1829 {
1830     Q_Q(QQuickTextInput);
1831     control->setParent(q);//Now mandatory due to accessibility changes
1832     control->setCursorWidth(1);
1833     control->setPasswordCharacter(QLatin1Char('*'));
1834     q->setSmooth(smooth);
1835     q->setAcceptedMouseButtons(Qt::LeftButton);
1836     q->setFlag(QQuickItem::ItemAcceptsInputMethod);
1837     q->setFlag(QQuickItem::ItemHasContents);
1838     q->connect(control, SIGNAL(cursorPositionChanged(int,int)),
1839                q, SLOT(cursorPosChanged()));
1840     q->connect(control, SIGNAL(selectionChanged()),
1841                q, SLOT(selectionChanged()));
1842     q->connect(control, SIGNAL(textChanged(QString)),
1843                q, SLOT(q_textChanged()));
1844     q->connect(control, SIGNAL(accepted()),
1845                q, SIGNAL(accepted()));
1846     q->connect(control, SIGNAL(updateNeeded(QRect)),
1847                q, SLOT(updateRect(QRect)));
1848 #ifndef QT_NO_CLIPBOARD
1849     q->connect(q, SIGNAL(readOnlyChanged(bool)),
1850             q, SLOT(q_canPasteChanged()));
1851     q->connect(QGuiApplication::clipboard(), SIGNAL(dataChanged()),
1852             q, SLOT(q_canPasteChanged()));
1853     canPaste = !control->isReadOnly() && QGuiApplication::clipboard()->text().length() != 0;
1854 #endif // QT_NO_CLIPBOARD
1855     q->connect(control, SIGNAL(updateMicroFocus()),
1856                q, SLOT(updateCursorRectangle()));
1857     q->connect(control, SIGNAL(displayTextChanged(QString)),
1858                q, SLOT(updateRect()));
1859     q->updateSize();
1860     imHints &= ~Qt::ImhMultiLine;
1861     oldValidity = control->hasAcceptableInput();
1862     lastSelectionStart = 0;
1863     lastSelectionEnd = 0;
1864     QPalette p = control->palette();
1865     selectedTextColor = p.color(QPalette::HighlightedText);
1866     selectionColor = p.color(QPalette::Highlight);
1867     determineHorizontalAlignment();
1868
1869     if (!qmlDisableDistanceField()) {
1870         QTextOption option = control->textLayout()->textOption();
1871         option.setUseDesignMetrics(true);
1872         control->textLayout()->setTextOption(option);
1873     }
1874 }
1875
1876 void QQuickTextInput::cursorPosChanged()
1877 {
1878     Q_D(QQuickTextInput);
1879     updateCursorRectangle();
1880     emit cursorPositionChanged();
1881     // XXX todo - not in 4.8?
1882 #if 0
1883     d->control->resetCursorBlinkTimer();
1884 #endif
1885
1886     if (!d->control->hasSelectedText()) {
1887         if (d->lastSelectionStart != d->control->cursor()) {
1888             d->lastSelectionStart = d->control->cursor();
1889             emit selectionStartChanged();
1890         }
1891         if (d->lastSelectionEnd != d->control->cursor()) {
1892             d->lastSelectionEnd = d->control->cursor();
1893             emit selectionEndChanged();
1894         }
1895     }
1896 }
1897
1898 void QQuickTextInput::updateCursorRectangle()
1899 {
1900     Q_D(QQuickTextInput);
1901     d->determineHorizontalAlignment();
1902     d->updateHorizontalScroll();
1903     updateRect();//TODO: Only update rect between pos's
1904     updateMicroFocus();
1905     emit cursorRectangleChanged();
1906     if (d->cursorItem)
1907         d->cursorItem->setX(d->control->cursorToX() - d->hscroll);
1908 }
1909
1910 void QQuickTextInput::selectionChanged()
1911 {
1912     Q_D(QQuickTextInput);
1913     updateRect();//TODO: Only update rect in selection
1914     emit selectedTextChanged();
1915
1916     if (d->lastSelectionStart != d->control->selectionStart()) {
1917         d->lastSelectionStart = d->control->selectionStart();
1918         if (d->lastSelectionStart == -1)
1919             d->lastSelectionStart = d->control->cursor();
1920         emit selectionStartChanged();
1921     }
1922     if (d->lastSelectionEnd != d->control->selectionEnd()) {
1923         d->lastSelectionEnd = d->control->selectionEnd();
1924         if (d->lastSelectionEnd == -1)
1925             d->lastSelectionEnd = d->control->cursor();
1926         emit selectionEndChanged();
1927     }
1928 }
1929
1930 void QQuickTextInput::q_textChanged()
1931 {
1932     Q_D(QQuickTextInput);
1933     emit textChanged();
1934     emit displayTextChanged();
1935     updateSize();
1936     d->determineHorizontalAlignment();
1937     d->updateHorizontalScroll();
1938     updateMicroFocus();
1939     if (hasAcceptableInput() != d->oldValidity) {
1940         d->oldValidity = hasAcceptableInput();
1941         emit acceptableInputChanged();
1942     }
1943 }
1944
1945 void QQuickTextInputPrivate::showCursor()
1946 {
1947     if (textNode != 0 && textNode->cursorNode() != 0)
1948         textNode->cursorNode()->setColor(color);
1949 }
1950
1951 void QQuickTextInputPrivate::hideCursor()
1952 {
1953     if (textNode != 0 && textNode->cursorNode() != 0)
1954         textNode->cursorNode()->setColor(QColor(0, 0, 0, 0));
1955 }
1956
1957 void QQuickTextInput::updateRect(const QRect &r)
1958 {
1959     Q_D(QQuickTextInput);
1960     if (!isComponentComplete())
1961         return;
1962
1963     if (r.isEmpty()) {
1964         d->textLayoutDirty = true;
1965     }
1966
1967     update();
1968 }
1969
1970 QRectF QQuickTextInput::boundingRect() const
1971 {
1972     Q_D(const QQuickTextInput);
1973     QRectF r = QQuickImplicitSizeItem::boundingRect();
1974
1975     int cursorWidth = d->cursorItem ? d->cursorItem->width() : d->control->cursorWidth();
1976
1977     // Could include font max left/right bearings to either side of rectangle.
1978
1979     r.setRight(r.right() + cursorWidth);
1980     return r;
1981 }
1982
1983 void QQuickTextInput::updateSize(bool needsRedraw)
1984 {
1985     Q_D(QQuickTextInput);
1986     int w = width();
1987     int h = height();
1988     setImplicitSize(d->calculateTextWidth(), d->control->height()-1); // -1 to counter QQuickLineControl's +1 which is not consistent with Text.
1989     if (w==width() && h==height() && needsRedraw)
1990         update();
1991 }
1992
1993 void QQuickTextInput::q_canPasteChanged()
1994 {
1995     Q_D(QQuickTextInput);
1996     bool old = d->canPaste;
1997 #ifndef QT_NO_CLIPBOARD
1998     d->canPaste = !d->control->isReadOnly() && QGuiApplication::clipboard()->text().length() != 0;
1999 #endif
2000     if (d->canPaste != old)
2001         emit canPasteChanged();
2002 }
2003
2004 QT_END_NAMESPACE
2005