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