Say hello to QtQuick module
[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             QFontMetrics fm = QFontMetrics(d->font);
1300             // the y offset is there to keep the baseline constant in case we have script changes in the text.
1301             QPoint offset(-d->hscroll, fm.ascent() - d->control->ascent());
1302             offset.rx() += d->control->cursorToX();
1303
1304             QRect br(boundingRect().toRect());
1305             cursorNode->setRect(QRectF(offset, QSizeF(d->control->cursorWidth(), br.height())));
1306
1307             if (!d->cursorVisible
1308                     || (!d->control->cursorBlinkStatus() && d->control->cursorBlinkPeriod() > 0)) {
1309                 d->hideCursor();
1310             } else {
1311                 d->showCursor();
1312             }
1313         }
1314     } else {
1315         node->deleteContent();
1316         node->setMatrix(QMatrix4x4());
1317
1318         QPoint offset = QPoint(0,0);
1319         QFontMetrics fm = QFontMetrics(d->font);
1320         QRect br(boundingRect().toRect());
1321         if (d->autoScroll) {
1322             // the y offset is there to keep the baseline constant in case we have script changes in the text.
1323             offset = br.topLeft() - QPoint(d->hscroll, d->control->ascent() - fm.ascent());
1324         } else {
1325             offset = QPoint(d->hscroll, 0);
1326         }
1327
1328         QTextLayout *textLayout = d->control->textLayout();
1329         if (!textLayout->text().isEmpty()) {
1330             node->addTextLayout(offset, textLayout, d->color,
1331                                 QQuickText::Normal, QColor(),
1332                                 d->selectionColor, d->selectedTextColor,
1333                                 d->control->selectionStart(),
1334                                 d->control->selectionEnd() - 1); // selectionEnd() returns first char after
1335                                                                  // selection
1336         }
1337
1338         if (!isReadOnly() && d->cursorItem == 0) {
1339             offset.rx() += d->control->cursorToX();
1340             node->setCursor(QRectF(offset, QSizeF(d->control->cursorWidth(), br.height())), d->color);
1341             if (!d->cursorVisible
1342                     || (!d->control->cursorBlinkStatus() && d->control->cursorBlinkPeriod() > 0)) {
1343                 d->hideCursor();
1344             } else {
1345                 d->showCursor();
1346             }
1347         }
1348
1349         d->textLayoutDirty = false;
1350     }
1351
1352     return node;
1353 }
1354
1355 QVariant QQuickTextInput::inputMethodQuery(Qt::InputMethodQuery property) const
1356 {
1357     Q_D(const QQuickTextInput);
1358     switch (property) {
1359     case Qt::ImEnabled:
1360         return QVariant((bool)(flags() & ItemAcceptsInputMethod));
1361     case Qt::ImHints:
1362         return QVariant((int)inputMethodHints());
1363     case Qt::ImCursorRectangle:
1364         return cursorRectangle();
1365     case Qt::ImFont:
1366         return font();
1367     case Qt::ImCursorPosition:
1368         return QVariant(d->control->cursor());
1369     case Qt::ImSurroundingText:
1370         if (d->control->echoMode() == QLineControl::PasswordEchoOnEdit
1371             && !d->control->passwordEchoEditing()) {
1372             return QVariant(displayText());
1373         } else {
1374             return QVariant(d->control->realText());
1375         }
1376     case Qt::ImCurrentSelection:
1377         return QVariant(selectedText());
1378     case Qt::ImMaximumTextLength:
1379         return QVariant(maxLength());
1380     case Qt::ImAnchorPosition:
1381         if (d->control->selectionStart() == d->control->selectionEnd())
1382             return QVariant(d->control->cursor());
1383         else if (d->control->selectionStart() == d->control->cursor())
1384             return QVariant(d->control->selectionEnd());
1385         else
1386             return QVariant(d->control->selectionStart());
1387     default:
1388         return QVariant();
1389     }
1390 }
1391
1392 /*!
1393     \qmlmethod void QtQuick2::TextInput::deselect()
1394
1395     Removes active text selection.
1396 */
1397 void QQuickTextInput::deselect()
1398 {
1399     Q_D(QQuickTextInput);
1400     d->control->deselect();
1401 }
1402
1403 /*!
1404     \qmlmethod void QtQuick2::TextInput::selectAll()
1405
1406     Causes all text to be selected.
1407 */
1408 void QQuickTextInput::selectAll()
1409 {
1410     Q_D(QQuickTextInput);
1411     d->control->setSelection(0, d->control->text().length());
1412 }
1413
1414 /*!
1415     \qmlmethod void QtQuick2::TextInput::isRightToLeft(int start, int end)
1416
1417     Returns true if the natural reading direction of the editor text
1418     found between positions \a start and \a end is right to left.
1419 */
1420 bool QQuickTextInput::isRightToLeft(int start, int end)
1421 {
1422     Q_D(QQuickTextInput);
1423     if (start > end) {
1424         qmlInfo(this) << "isRightToLeft(start, end) called with the end property being smaller than the start.";
1425         return false;
1426     } else {
1427         return d->control->text().mid(start, end - start).isRightToLeft();
1428     }
1429 }
1430
1431 #ifndef QT_NO_CLIPBOARD
1432 /*!
1433     \qmlmethod QtQuick2::TextInput::cut()
1434
1435     Moves the currently selected text to the system clipboard.
1436 */
1437 void QQuickTextInput::cut()
1438 {
1439     Q_D(QQuickTextInput);
1440     d->control->copy();
1441     d->control->del();
1442 }
1443
1444 /*!
1445     \qmlmethod QtQuick2::TextInput::copy()
1446
1447     Copies the currently selected text to the system clipboard.
1448 */
1449 void QQuickTextInput::copy()
1450 {
1451     Q_D(QQuickTextInput);
1452     d->control->copy();
1453 }
1454
1455 /*!
1456     \qmlmethod QtQuick2::TextInput::paste()
1457
1458     Replaces the currently selected text by the contents of the system clipboard.
1459 */
1460 void QQuickTextInput::paste()
1461 {
1462     Q_D(QQuickTextInput);
1463     if (!d->control->isReadOnly())
1464         d->control->paste();
1465 }
1466 #endif // QT_NO_CLIPBOARD
1467
1468 /*!
1469     \qmlmethod void QtQuick2::TextInput::selectWord()
1470
1471     Causes the word closest to the current cursor position to be selected.
1472 */
1473 void QQuickTextInput::selectWord()
1474 {
1475     Q_D(QQuickTextInput);
1476     d->control->selectWordAtPos(d->control->cursor());
1477 }
1478
1479 /*!
1480     \qmlproperty bool QtQuick2::TextInput::smooth
1481
1482     This property holds whether the text is smoothly scaled or transformed.
1483
1484     Smooth filtering gives better visual quality, but is slower.  If
1485     the item is displayed at its natural size, this property has no visual or
1486     performance effect.
1487
1488     \note Generally scaling artifacts are only visible if the item is stationary on
1489     the screen.  A common pattern when animating an item is to disable smooth
1490     filtering at the beginning of the animation and reenable it at the conclusion.
1491 */
1492
1493 /*!
1494    \qmlproperty string QtQuick2::TextInput::passwordCharacter
1495
1496    This is the character displayed when echoMode is set to Password or
1497    PasswordEchoOnEdit. By default it is an asterisk.
1498
1499    If this property is set to a string with more than one character,
1500    the first character is used. If the string is empty, the value
1501    is ignored and the property is not set.
1502 */
1503 QString QQuickTextInput::passwordCharacter() const
1504 {
1505     Q_D(const QQuickTextInput);
1506     return QString(d->control->passwordCharacter());
1507 }
1508
1509 void QQuickTextInput::setPasswordCharacter(const QString &str)
1510 {
1511     Q_D(QQuickTextInput);
1512     if (str.length() < 1)
1513         return;
1514     d->control->setPasswordCharacter(str.constData()[0]);
1515     EchoMode echoMode_ = echoMode();
1516     if (echoMode_ == Password || echoMode_ == PasswordEchoOnEdit) {
1517         updateSize();
1518     }
1519     emit passwordCharacterChanged();
1520 }
1521
1522 /*!
1523    \qmlproperty string QtQuick2::TextInput::displayText
1524
1525    This is the text displayed in the TextInput.
1526
1527    If \l echoMode is set to TextInput::Normal, this holds the
1528    same value as the TextInput::text property. Otherwise,
1529    this property holds the text visible to the user, while
1530    the \l text property holds the actual entered text.
1531 */
1532 QString QQuickTextInput::displayText() const
1533 {
1534     Q_D(const QQuickTextInput);
1535     return d->control->displayText();
1536 }
1537
1538 /*!
1539     \qmlproperty bool QtQuick2::TextInput::selectByMouse
1540
1541     Defaults to false.
1542
1543     If true, the user can use the mouse to select text in some
1544     platform-specific way. Note that for some platforms this may
1545     not be an appropriate interaction (eg. may conflict with how
1546     the text needs to behave inside a Flickable.
1547 */
1548 bool QQuickTextInput::selectByMouse() const
1549 {
1550     Q_D(const QQuickTextInput);
1551     return d->selectByMouse;
1552 }
1553
1554 void QQuickTextInput::setSelectByMouse(bool on)
1555 {
1556     Q_D(QQuickTextInput);
1557     if (d->selectByMouse != on) {
1558         d->selectByMouse = on;
1559         emit selectByMouseChanged(on);
1560     }
1561 }
1562
1563 /*!
1564     \qmlproperty enum QtQuick2::TextInput::mouseSelectionMode
1565
1566     Specifies how text should be selected using a mouse.
1567
1568     \list
1569     \o TextInput.SelectCharacters - The selection is updated with individual characters. (Default)
1570     \o TextInput.SelectWords - The selection is updated with whole words.
1571     \endlist
1572
1573     This property only applies when \l selectByMouse is true.
1574 */
1575
1576 QQuickTextInput::SelectionMode QQuickTextInput::mouseSelectionMode() const
1577 {
1578     Q_D(const QQuickTextInput);
1579     return d->mouseSelectionMode;
1580 }
1581
1582 void QQuickTextInput::setMouseSelectionMode(SelectionMode mode)
1583 {
1584     Q_D(QQuickTextInput);
1585     if (d->mouseSelectionMode != mode) {
1586         d->mouseSelectionMode = mode;
1587         emit mouseSelectionModeChanged(mode);
1588     }
1589 }
1590
1591 /*!
1592     \qmlproperty bool QtQuick2::TextInput::canPaste
1593
1594     Returns true if the TextInput is writable and the content of the clipboard is
1595     suitable for pasting into the TextEdit.
1596 */
1597 bool QQuickTextInput::canPaste() const
1598 {
1599     Q_D(const QQuickTextInput);
1600     return d->canPaste;
1601 }
1602
1603 void QQuickTextInput::moveCursorSelection(int position)
1604 {
1605     Q_D(QQuickTextInput);
1606     d->control->moveCursor(position, true);
1607 }
1608
1609 /*!
1610     \qmlmethod void QtQuick2::TextInput::moveCursorSelection(int position, SelectionMode mode = TextInput.SelectCharacters)
1611
1612     Moves the cursor to \a position and updates the selection according to the optional \a mode
1613     parameter.  (To only move the cursor, set the \l cursorPosition property.)
1614
1615     When this method is called it additionally sets either the
1616     selectionStart or the selectionEnd (whichever was at the previous cursor position)
1617     to the specified position. This allows you to easily extend and contract the selected
1618     text range.
1619
1620     The selection mode specifies whether the selection is updated on a per character or a per word
1621     basis.  If not specified the selection mode will default to TextInput.SelectCharacters.
1622
1623     \list
1624     \o TextEdit.SelectCharacters - Sets either the selectionStart or selectionEnd (whichever was at
1625     the previous cursor position) to the specified position.
1626     \o TextEdit.SelectWords - Sets the selectionStart and selectionEnd to include all
1627     words between the specified position and the previous cursor position.  Words partially in the
1628     range are included.
1629     \endlist
1630
1631     For example, take this sequence of calls:
1632
1633     \code
1634         cursorPosition = 5
1635         moveCursorSelection(9, TextInput.SelectCharacters)
1636         moveCursorSelection(7, TextInput.SelectCharacters)
1637     \endcode
1638
1639     This moves the cursor to position 5, extend the selection end from 5 to 9
1640     and then retract the selection end from 9 to 7, leaving the text from position 5 to 7
1641     selected (the 6th and 7th characters).
1642
1643     The same sequence with TextInput.SelectWords will extend the selection start to a word boundary
1644     before or on position 5 and extend the selection end to a word boundary on or past position 9.
1645 */
1646 void QQuickTextInput::moveCursorSelection(int pos, SelectionMode mode)
1647 {
1648     Q_D(QQuickTextInput);
1649
1650     if (mode == SelectCharacters) {
1651         d->control->moveCursor(pos, true);
1652     } else if (pos != d->control->cursor()){
1653         const int cursor = d->control->cursor();
1654         int anchor;
1655         if (!d->control->hasSelectedText())
1656             anchor = d->control->cursor();
1657         else if (d->control->selectionStart() == d->control->cursor())
1658             anchor = d->control->selectionEnd();
1659         else
1660             anchor = d->control->selectionStart();
1661
1662         if (anchor < pos || (anchor == pos && cursor < pos)) {
1663             const QString text = d->control->text();
1664             QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
1665             finder.setPosition(anchor);
1666
1667             const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
1668             if (anchor < text.length() && (!(reasons & QTextBoundaryFinder::StartWord)
1669                     || ((reasons & QTextBoundaryFinder::EndWord) && anchor > cursor))) {
1670                 finder.toPreviousBoundary();
1671             }
1672             anchor = finder.position() != -1 ? finder.position() : 0;
1673
1674             finder.setPosition(pos);
1675             if (pos > 0 && !finder.boundaryReasons())
1676                 finder.toNextBoundary();
1677             const int cursor = finder.position() != -1 ? finder.position() : text.length();
1678
1679             d->control->setSelection(anchor, cursor - anchor);
1680         } else if (anchor > pos || (anchor == pos && cursor > pos)) {
1681             const QString text = d->control->text();
1682             QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
1683             finder.setPosition(anchor);
1684
1685             const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
1686             if (anchor > 0 && (!(reasons & QTextBoundaryFinder::EndWord)
1687                     || ((reasons & QTextBoundaryFinder::StartWord) && anchor < cursor))) {
1688                 finder.toNextBoundary();
1689             }
1690
1691             anchor = finder.position() != -1 ? finder.position() : text.length();
1692
1693             finder.setPosition(pos);
1694             if (pos < text.length() && !finder.boundaryReasons())
1695                  finder.toPreviousBoundary();
1696             const int cursor = finder.position() != -1 ? finder.position() : 0;
1697
1698             d->control->setSelection(anchor, cursor - anchor);
1699         }
1700     }
1701 }
1702
1703 /*!
1704     \qmlmethod void QtQuick2::TextInput::openSoftwareInputPanel()
1705
1706     Opens software input panels like virtual keyboards for typing, useful for
1707     customizing when you want the input keyboard to be shown and hidden in
1708     your application.
1709
1710     By default the opening of input panels follows the platform style. Input panels are
1711     always closed if no editor has active focus.
1712
1713     You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
1714     and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
1715     the behavior you want.
1716
1717     Only relevant on platforms, which provide virtual keyboards.
1718
1719     \qml
1720         import QtQuick 1.0
1721         TextInput {
1722             id: textInput
1723             text: "Hello world!"
1724             activeFocusOnPress: false
1725             MouseArea {
1726                 anchors.fill: parent
1727                 onClicked: {
1728                     if (!textInput.activeFocus) {
1729                         textInput.forceActiveFocus()
1730                         textInput.openSoftwareInputPanel();
1731                     } else {
1732                         textInput.focus = false;
1733                     }
1734                 }
1735                 onPressAndHold: textInput.closeSoftwareInputPanel();
1736             }
1737         }
1738     \endqml
1739 */
1740 void QQuickTextInput::openSoftwareInputPanel()
1741 {
1742     if (qGuiApp)
1743         qGuiApp->inputPanel()->show();
1744 }
1745
1746 /*!
1747     \qmlmethod void QtQuick2::TextInput::closeSoftwareInputPanel()
1748
1749     Closes a software input panel like a virtual keyboard shown on the screen, useful
1750     for customizing when you want the input keyboard to be shown and hidden in
1751     your application.
1752
1753     By default the opening of input panels follows the platform style. Input panels are
1754     always closed if no editor has active focus.
1755
1756     You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
1757     and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
1758     the behavior you want.
1759
1760     Only relevant on platforms, which provide virtual keyboards.
1761
1762     \qml
1763         import QtQuick 1.0
1764         TextInput {
1765             id: textInput
1766             text: "Hello world!"
1767             activeFocusOnPress: false
1768             MouseArea {
1769                 anchors.fill: parent
1770                 onClicked: {
1771                     if (!textInput.activeFocus) {
1772                         textInput.forceActiveFocus();
1773                         textInput.openSoftwareInputPanel();
1774                     } else {
1775                         textInput.focus = false;
1776                     }
1777                 }
1778                 onPressAndHold: textInput.closeSoftwareInputPanel();
1779             }
1780         }
1781     \endqml
1782 */
1783 void QQuickTextInput::closeSoftwareInputPanel()
1784 {
1785     if (qGuiApp)
1786         qGuiApp->inputPanel()->hide();
1787 }
1788
1789 void QQuickTextInput::focusInEvent(QFocusEvent *event)
1790 {
1791     Q_D(const QQuickTextInput);
1792     if (d->focusOnPress && !isReadOnly())
1793         openSoftwareInputPanel();
1794     QQuickImplicitSizeItem::focusInEvent(event);
1795 }
1796
1797 void QQuickTextInput::itemChange(ItemChange change, const ItemChangeData &value)
1798 {
1799     Q_D(QQuickTextInput);
1800     if (change == ItemActiveFocusHasChanged) {
1801         bool hasFocus = value.boolValue;
1802         d->focused = hasFocus;
1803         setCursorVisible(hasFocus); // ### refactor:  && d->canvas && d->canvas->hasFocus()
1804         if (echoMode() == QQuickTextInput::PasswordEchoOnEdit && !hasFocus)
1805             d->control->updatePasswordEchoEditing(false);//QLineControl sets it on key events, but doesn't deal with focus events
1806         if (!hasFocus)
1807             d->control->deselect();
1808     }
1809     QQuickItem::itemChange(change, value);
1810 }
1811
1812 /*!
1813     \qmlproperty bool QtQuick2::TextInput::inputMethodComposing
1814
1815
1816     This property holds whether the TextInput has partial text input from an
1817     input method.
1818
1819     While it is composing an input method may rely on mouse or key events from
1820     the TextInput to edit or commit the partial text.  This property can be
1821     used to determine when to disable events handlers that may interfere with
1822     the correct operation of an input method.
1823 */
1824 bool QQuickTextInput::isInputMethodComposing() const
1825 {
1826     Q_D(const QQuickTextInput);
1827     return d->control->preeditAreaText().length() > 0;
1828 }
1829
1830 void QQuickTextInputPrivate::init()
1831 {
1832     Q_Q(QQuickTextInput);
1833     control->setParent(q);//Now mandatory due to accessibility changes
1834     control->setCursorWidth(1);
1835     control->setPasswordCharacter(QLatin1Char('*'));
1836     q->setSmooth(smooth);
1837     q->setAcceptedMouseButtons(Qt::LeftButton);
1838     q->setFlag(QQuickItem::ItemAcceptsInputMethod);
1839     q->setFlag(QQuickItem::ItemHasContents);
1840     q->connect(control, SIGNAL(cursorPositionChanged(int,int)),
1841                q, SLOT(cursorPosChanged()));
1842     q->connect(control, SIGNAL(selectionChanged()),
1843                q, SLOT(selectionChanged()));
1844     q->connect(control, SIGNAL(textChanged(QString)),
1845                q, SLOT(q_textChanged()));
1846     q->connect(control, SIGNAL(accepted()),
1847                q, SIGNAL(accepted()));
1848     q->connect(control, SIGNAL(updateNeeded(QRect)),
1849                q, SLOT(updateRect(QRect)));
1850 #ifndef QT_NO_CLIPBOARD
1851     q->connect(q, SIGNAL(readOnlyChanged(bool)),
1852             q, SLOT(q_canPasteChanged()));
1853     q->connect(QGuiApplication::clipboard(), SIGNAL(dataChanged()),
1854             q, SLOT(q_canPasteChanged()));
1855     canPaste = !control->isReadOnly() && QGuiApplication::clipboard()->text().length() != 0;
1856 #endif // QT_NO_CLIPBOARD
1857     q->connect(control, SIGNAL(updateMicroFocus()),
1858                q, SLOT(updateCursorRectangle()));
1859     q->connect(control, SIGNAL(displayTextChanged(QString)),
1860                q, SLOT(updateRect()));
1861     q->updateSize();
1862     imHints &= ~Qt::ImhMultiLine;
1863     oldValidity = control->hasAcceptableInput();
1864     lastSelectionStart = 0;
1865     lastSelectionEnd = 0;
1866     QPalette p = control->palette();
1867     selectedTextColor = p.color(QPalette::HighlightedText);
1868     selectionColor = p.color(QPalette::Highlight);
1869     determineHorizontalAlignment();
1870
1871     if (!qmlDisableDistanceField()) {
1872         QTextOption option = control->textLayout()->textOption();
1873         option.setUseDesignMetrics(true);
1874         control->textLayout()->setTextOption(option);
1875     }
1876 }
1877
1878 void QQuickTextInput::cursorPosChanged()
1879 {
1880     Q_D(QQuickTextInput);
1881     updateCursorRectangle();
1882     emit cursorPositionChanged();
1883     // XXX todo - not in 4.8?
1884 #if 0
1885     d->control->resetCursorBlinkTimer();
1886 #endif
1887
1888     if (!d->control->hasSelectedText()) {
1889         if (d->lastSelectionStart != d->control->cursor()) {
1890             d->lastSelectionStart = d->control->cursor();
1891             emit selectionStartChanged();
1892         }
1893         if (d->lastSelectionEnd != d->control->cursor()) {
1894             d->lastSelectionEnd = d->control->cursor();
1895             emit selectionEndChanged();
1896         }
1897     }
1898 }
1899
1900 void QQuickTextInput::updateCursorRectangle()
1901 {
1902     Q_D(QQuickTextInput);
1903     d->determineHorizontalAlignment();
1904     d->updateHorizontalScroll();
1905     updateRect();//TODO: Only update rect between pos's
1906     updateMicroFocus();
1907     emit cursorRectangleChanged();
1908     if (d->cursorItem)
1909         d->cursorItem->setX(d->control->cursorToX() - d->hscroll);
1910 }
1911
1912 void QQuickTextInput::selectionChanged()
1913 {
1914     Q_D(QQuickTextInput);
1915     updateRect();//TODO: Only update rect in selection
1916     emit selectedTextChanged();
1917
1918     if (d->lastSelectionStart != d->control->selectionStart()) {
1919         d->lastSelectionStart = d->control->selectionStart();
1920         if (d->lastSelectionStart == -1)
1921             d->lastSelectionStart = d->control->cursor();
1922         emit selectionStartChanged();
1923     }
1924     if (d->lastSelectionEnd != d->control->selectionEnd()) {
1925         d->lastSelectionEnd = d->control->selectionEnd();
1926         if (d->lastSelectionEnd == -1)
1927             d->lastSelectionEnd = d->control->cursor();
1928         emit selectionEndChanged();
1929     }
1930 }
1931
1932 void QQuickTextInput::q_textChanged()
1933 {
1934     Q_D(QQuickTextInput);
1935     emit textChanged();
1936     emit displayTextChanged();
1937     updateSize();
1938     d->determineHorizontalAlignment();
1939     d->updateHorizontalScroll();
1940     updateMicroFocus();
1941     if (hasAcceptableInput() != d->oldValidity) {
1942         d->oldValidity = hasAcceptableInput();
1943         emit acceptableInputChanged();
1944     }
1945 }
1946
1947 void QQuickTextInputPrivate::showCursor()
1948 {
1949     if (textNode != 0 && textNode->cursorNode() != 0)
1950         textNode->cursorNode()->setColor(color);
1951 }
1952
1953 void QQuickTextInputPrivate::hideCursor()
1954 {
1955     if (textNode != 0 && textNode->cursorNode() != 0)
1956         textNode->cursorNode()->setColor(QColor(0, 0, 0, 0));
1957 }
1958
1959 void QQuickTextInput::updateRect(const QRect &r)
1960 {
1961     Q_D(QQuickTextInput);
1962     if (!isComponentComplete())
1963         return;
1964
1965     if (r.isEmpty()) {
1966         d->textLayoutDirty = true;
1967     }
1968
1969     update();
1970 }
1971
1972 QRectF QQuickTextInput::boundingRect() const
1973 {
1974     Q_D(const QQuickTextInput);
1975     QRectF r = QQuickImplicitSizeItem::boundingRect();
1976
1977     int cursorWidth = d->cursorItem ? d->cursorItem->width() : d->control->cursorWidth();
1978
1979     // Could include font max left/right bearings to either side of rectangle.
1980
1981     r.setRight(r.right() + cursorWidth);
1982     return r;
1983 }
1984
1985 void QQuickTextInput::updateSize(bool needsRedraw)
1986 {
1987     Q_D(QQuickTextInput);
1988     int w = width();
1989     int h = height();
1990     setImplicitSize(d->calculateTextWidth(), d->control->height()-1); // -1 to counter QLineControl's +1 which is not consistent with Text.
1991     if (w==width() && h==height() && needsRedraw)
1992         update();
1993 }
1994
1995 void QQuickTextInput::q_canPasteChanged()
1996 {
1997     Q_D(QQuickTextInput);
1998     bool old = d->canPaste;
1999 #ifndef QT_NO_CLIPBOARD
2000     d->canPaste = !d->control->isReadOnly() && QGuiApplication::clipboard()->text().length() != 0;
2001 #endif
2002     if (d->canPaste != old)
2003         emit canPasteChanged();
2004 }
2005
2006 QT_END_NAMESPACE
2007