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