d30faadb34115a1eca5824b45faa599bcce7a6ff
[profile/ivi/qtdeclarative.git] / src / declarative / items / qsgtextinput.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 "qsgtextinput_p.h"
43 #include "qsgtextinput_p_p.h"
44 #include "qsgcanvas.h"
45
46 #include <private/qdeclarativeglobal_p.h>
47 #include <private/qwidget_p.h>
48 #include <private/qsgdistancefieldglyphcache_p.h>
49
50 #include <QtDeclarative/qdeclarativeinfo.h>
51 #include <QtWidgets/qgraphicssceneevent.h>
52 #include <QtWidgets/qinputcontext.h>
53 #include <QTextBoundaryFinder>
54 #include <qstyle.h>
55 #include <qsgtextnode_p.h>
56 #include <qsgsimplerectnode.h>
57
58 QT_BEGIN_NAMESPACE
59
60 DEFINE_BOOL_CONFIG_OPTION(qmlDisableDistanceField, QML_DISABLE_DISTANCEFIELD)
61
62 QWidgetPrivate *qt_widget_private(QWidget *widget);
63
64 /*!
65     \qmlclass TextInput QSGTextInput
66     \inqmlmodule QtQuick 2
67     \ingroup qml-basic-visual-elements
68     \brief The TextInput item displays an editable line of text.
69     \inherits Item
70
71     The TextInput element displays a single line of editable plain text.
72
73     TextInput is used to accept a line of text input. Input constraints
74     can be placed on a TextInput item (for example, through a \l validator or \l inputMask),
75     and setting \l echoMode to an appropriate value enables TextInput to be used for
76     a password input field.
77
78     On Mac OS X, the Up/Down key bindings for Home/End are explicitly disabled.
79     If you want such bindings (on any platform), you will need to construct them in QML.
80
81     \sa TextEdit, Text, {declarative/text/textselection}{Text Selection example}
82 */
83 QSGTextInput::QSGTextInput(QSGItem* parent)
84 : QSGImplicitSizeItem(*(new QSGTextInputPrivate), parent)
85 {
86     Q_D(QSGTextInput);
87     d->init();
88 }
89
90 QSGTextInput::~QSGTextInput()
91 {
92 }
93
94 /*!
95     \qmlproperty string QtQuick2::TextInput::text
96
97     The text in the TextInput.
98 */
99 QString QSGTextInput::text() const
100 {
101     Q_D(const QSGTextInput);
102     return d->control->text();
103 }
104
105 void QSGTextInput::setText(const QString &s)
106 {
107     Q_D(QSGTextInput);
108     if(s == text())
109         return;
110     d->control->setText(s);
111 }
112
113 /*!
114     \qmlproperty string QtQuick2::TextInput::font.family
115
116     Sets the family name of the font.
117
118     The family name is case insensitive and may optionally include a foundry name, e.g. "Helvetica [Cronyx]".
119     If the family is available from more than one foundry and the foundry isn't specified, an arbitrary foundry is chosen.
120     If the family isn't available a family will be set using the font matching algorithm.
121 */
122
123 /*!
124     \qmlproperty bool QtQuick2::TextInput::font.bold
125
126     Sets whether the font weight is bold.
127 */
128
129 /*!
130     \qmlproperty enumeration QtQuick2::TextInput::font.weight
131
132     Sets the font's weight.
133
134     The weight can be one of:
135     \list
136     \o Font.Light
137     \o Font.Normal - the default
138     \o Font.DemiBold
139     \o Font.Bold
140     \o Font.Black
141     \endlist
142
143     \qml
144     TextInput { text: "Hello"; font.weight: Font.DemiBold }
145     \endqml
146 */
147
148 /*!
149     \qmlproperty bool QtQuick2::TextInput::font.italic
150
151     Sets whether the font has an italic style.
152 */
153
154 /*!
155     \qmlproperty bool QtQuick2::TextInput::font.underline
156
157     Sets whether the text is underlined.
158 */
159
160 /*!
161     \qmlproperty bool QtQuick2::TextInput::font.strikeout
162
163     Sets whether the font has a strikeout style.
164 */
165
166 /*!
167     \qmlproperty real QtQuick2::TextInput::font.pointSize
168
169     Sets the font size in points. The point size must be greater than zero.
170 */
171
172 /*!
173     \qmlproperty int QtQuick2::TextInput::font.pixelSize
174
175     Sets the font size in pixels.
176
177     Using this function makes the font device dependent.
178     Use \c pointSize to set the size of the font in a device independent manner.
179 */
180
181 /*!
182     \qmlproperty real QtQuick2::TextInput::font.letterSpacing
183
184     Sets the letter spacing for the font.
185
186     Letter spacing changes the default spacing between individual letters in the font.
187     A positive value increases the letter spacing by the corresponding pixels; a negative value decreases the spacing.
188 */
189
190 /*!
191     \qmlproperty real QtQuick2::TextInput::font.wordSpacing
192
193     Sets the word spacing for the font.
194
195     Word spacing changes the default spacing between individual words.
196     A positive value increases the word spacing by a corresponding amount of pixels,
197     while a negative value decreases the inter-word spacing accordingly.
198 */
199
200 /*!
201     \qmlproperty enumeration QtQuick2::TextInput::font.capitalization
202
203     Sets the capitalization for the text.
204
205     \list
206     \o Font.MixedCase - This is the normal text rendering option where no capitalization change is applied.
207     \o Font.AllUppercase - This alters the text to be rendered in all uppercase type.
208     \o Font.AllLowercase         - This alters the text to be rendered in all lowercase type.
209     \o Font.SmallCaps - This alters the text to be rendered in small-caps type.
210     \o Font.Capitalize - This alters the text to be rendered with the first character of each word as an uppercase character.
211     \endlist
212
213     \qml
214     TextInput { text: "Hello"; font.capitalization: Font.AllLowercase }
215     \endqml
216 */
217
218 QFont QSGTextInput::font() const
219 {
220     Q_D(const QSGTextInput);
221     return d->sourceFont;
222 }
223
224 void QSGTextInput::setFont(const QFont &font)
225 {
226     Q_D(QSGTextInput);
227     if (d->sourceFont == font)
228         return;
229
230     d->sourceFont = font;
231     QFont oldFont = d->font;
232     d->font = font;
233     if (d->font.pointSizeF() != -1) {
234         // 0.5pt resolution
235         qreal size = qRound(d->font.pointSizeF()*2.0);
236         d->font.setPointSizeF(size/2.0);
237     }
238     if (oldFont != d->font) {
239         d->control->setFont(d->font);
240         updateSize();
241         updateCursorRectangle();
242         if(d->cursorItem){
243             d->cursorItem->setHeight(QFontMetrics(d->font).height());
244         }
245     }
246     emit fontChanged(d->sourceFont);
247 }
248
249 /*!
250     \qmlproperty color QtQuick2::TextInput::color
251
252     The text color.
253 */
254 QColor QSGTextInput::color() const
255 {
256     Q_D(const QSGTextInput);
257     return d->color;
258 }
259
260 void QSGTextInput::setColor(const QColor &c)
261 {
262     Q_D(QSGTextInput);
263     if (c != d->color) {
264         d->color = c;
265         update();
266         emit colorChanged(c);
267     }
268 }
269
270
271 /*!
272     \qmlproperty color QtQuick2::TextInput::selectionColor
273
274     The text highlight color, used behind selections.
275 */
276 QColor QSGTextInput::selectionColor() const
277 {
278     Q_D(const QSGTextInput);
279     return d->selectionColor;
280 }
281
282 void QSGTextInput::setSelectionColor(const QColor &color)
283 {
284     Q_D(QSGTextInput);
285     if (d->selectionColor == color)
286         return;
287
288     d->selectionColor = color;
289     QPalette p = d->control->palette();
290     p.setColor(QPalette::Highlight, d->selectionColor);
291     d->control->setPalette(p);
292     if (d->control->hasSelectedText())
293         update();
294     emit selectionColorChanged(color);
295 }
296 /*!
297     \qmlproperty color QtQuick2::TextInput::selectedTextColor
298
299     The highlighted text color, used in selections.
300 */
301 QColor QSGTextInput::selectedTextColor() const
302 {
303     Q_D(const QSGTextInput);
304     return d->selectedTextColor;
305 }
306
307 void QSGTextInput::setSelectedTextColor(const QColor &color)
308 {
309     Q_D(QSGTextInput);
310     if (d->selectedTextColor == color)
311         return;
312
313     d->selectedTextColor = color;
314     QPalette p = d->control->palette();
315     p.setColor(QPalette::HighlightedText, d->selectedTextColor);
316     d->control->setPalette(p);
317     if (d->control->hasSelectedText())
318         update();
319     emit selectedTextColorChanged(color);
320 }
321
322 /*!
323     \qmlproperty enumeration QtQuick2::TextInput::horizontalAlignment
324     \qmlproperty enumeration QtQuick2::TextInput::effectiveHorizontalAlignment
325
326     Sets the horizontal alignment of the text within the TextInput item's
327     width and height. By default, the text alignment follows the natural alignment
328     of the text, for example text that is read from left to right will be aligned to
329     the left.
330
331     TextInput does not have vertical alignment, as the natural height is
332     exactly the height of the single line of text. If you set the height
333     manually to something larger, TextInput will always be top aligned
334     vertically. You can use anchors to align it however you want within
335     another item.
336
337     The valid values for \c horizontalAlignment are \c TextInput.AlignLeft, \c TextInput.AlignRight and
338     \c TextInput.AlignHCenter.
339
340     When using the attached property LayoutMirroring::enabled to mirror application
341     layouts, the horizontal alignment of text will also be mirrored. However, the property
342     \c horizontalAlignment will remain unchanged. To query the effective horizontal alignment
343     of TextInput, use the read-only property \c effectiveHorizontalAlignment.
344 */
345 QSGTextInput::HAlignment QSGTextInput::hAlign() const
346 {
347     Q_D(const QSGTextInput);
348     return d->hAlign;
349 }
350
351 void QSGTextInput::setHAlign(HAlignment align)
352 {
353     Q_D(QSGTextInput);
354     bool forceAlign = d->hAlignImplicit && d->effectiveLayoutMirror;
355     d->hAlignImplicit = false;
356     if (d->setHAlign(align, forceAlign) && isComponentComplete()) {
357         updateCursorRectangle();
358     }
359 }
360
361 void QSGTextInput::resetHAlign()
362 {
363     Q_D(QSGTextInput);
364     d->hAlignImplicit = true;
365     if (d->determineHorizontalAlignment() && isComponentComplete()) {
366         updateCursorRectangle();
367     }
368 }
369
370 QSGTextInput::HAlignment QSGTextInput::effectiveHAlign() const
371 {
372     Q_D(const QSGTextInput);
373     QSGTextInput::HAlignment effectiveAlignment = d->hAlign;
374     if (!d->hAlignImplicit && d->effectiveLayoutMirror) {
375         switch (d->hAlign) {
376         case QSGTextInput::AlignLeft:
377             effectiveAlignment = QSGTextInput::AlignRight;
378             break;
379         case QSGTextInput::AlignRight:
380             effectiveAlignment = QSGTextInput::AlignLeft;
381             break;
382         default:
383             break;
384         }
385     }
386     return effectiveAlignment;
387 }
388
389 bool QSGTextInputPrivate::setHAlign(QSGTextInput::HAlignment alignment, bool forceAlign)
390 {
391     Q_Q(QSGTextInput);
392     if ((hAlign != alignment || forceAlign) && alignment <= QSGTextInput::AlignHCenter) { // justify not supported
393         QSGTextInput::HAlignment oldEffectiveHAlign = q->effectiveHAlign();
394         hAlign = alignment;
395         emit q->horizontalAlignmentChanged(alignment);
396         if (oldEffectiveHAlign != q->effectiveHAlign())
397             emit q->effectiveHorizontalAlignmentChanged();
398         return true;
399     }
400     return false;
401 }
402
403 bool QSGTextInputPrivate::determineHorizontalAlignment()
404 {
405     if (hAlignImplicit) {
406         // if no explicit alignment has been set, follow the natural layout direction of the text
407         QString text = control->text();
408         bool isRightToLeft = text.isEmpty() ? QApplication::keyboardInputDirection() == Qt::RightToLeft : text.isRightToLeft();
409         return setHAlign(isRightToLeft ? QSGTextInput::AlignRight : QSGTextInput::AlignLeft);
410     }
411     return false;
412 }
413
414 void QSGTextInputPrivate::mirrorChange()
415 {
416     Q_Q(QSGTextInput);
417     if (q->isComponentComplete()) {
418         if (!hAlignImplicit && (hAlign == QSGTextInput::AlignRight || hAlign == QSGTextInput::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 QSGTextInput::isReadOnly() const
435 {
436     Q_D(const QSGTextInput);
437     return d->control->isReadOnly();
438 }
439
440 void QSGTextInput::setReadOnly(bool ro)
441 {
442     Q_D(QSGTextInput);
443     if (d->control->isReadOnly() == ro)
444         return;
445
446     setFlag(QSGItem::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 QSGTextInput::maxLength() const
463 {
464     Q_D(const QSGTextInput);
465     return d->control->maxLength();
466 }
467
468 void QSGTextInput::setMaxLength(int ml)
469 {
470     Q_D(QSGTextInput);
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 QSGTextInput::isCursorVisible() const
506 {
507     Q_D(const QSGTextInput);
508     return d->cursorVisible;
509 }
510
511 void QSGTextInput::setCursorVisible(bool on)
512 {
513     Q_D(QSGTextInput);
514     if (d->cursorVisible == on)
515         return;
516     d->cursorVisible = on;
517     d->control->setCursorBlinkPeriod(on?QApplication::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 QSGTextInput::cursorPosition() const
531 {
532     Q_D(const QSGTextInput);
533     return d->control->cursor();
534 }
535 void QSGTextInput::setCursorPosition(int cp)
536 {
537     Q_D(QSGTextInput);
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 QSGTextInput::cursorRectangle() const
548 {
549     Q_D(const QSGTextInput);
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 QSGTextInput::selectionStart() const
568 {
569     Q_D(const QSGTextInput);
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 QSGTextInput::selectionEnd() const
583 {
584     Q_D(const QSGTextInput);
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 QSGTextInput::select(int start, int end)
601 {
602     Q_D(QSGTextInput);
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 QSGTextInput::selectedText() const
623 {
624     Q_D(const QSGTextInput);
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 QSGTextInput::focusOnPress() const
635 {
636     Q_D(const QSGTextInput);
637     return d->focusOnPress;
638 }
639
640 void QSGTextInput::setFocusOnPress(bool b)
641 {
642     Q_D(QSGTextInput);
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 QSGTextInput::autoScroll() const
657 {
658     Q_D(const QSGTextInput);
659     return d->autoScroll;
660 }
661
662 void QSGTextInput::setAutoScroll(bool b)
663 {
664     Q_D(QSGTextInput);
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* QSGTextInput::validator() const
785 {
786     Q_D(const QSGTextInput);
787     //###const cast isn't good, but needed for property system?
788     return const_cast<QValidator*>(d->control->validator());
789 }
790
791 void QSGTextInput::setValidator(QValidator* v)
792 {
793     Q_D(QSGTextInput);
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 QSGTextInput::inputMask() const
817 {
818     Q_D(const QSGTextInput);
819     return d->control->inputMask();
820 }
821
822 void QSGTextInput::setInputMask(const QString &im)
823 {
824     Q_D(QSGTextInput);
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 QSGTextInput::hasAcceptableInput() const
841 {
842     Q_D(const QSGTextInput);
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 QSGTextInputPrivate::updateInputMethodHints()
856 {
857     Q_Q(QSGTextInput);
858     Qt::InputMethodHints hints = inputMethodHints;
859     uint echo = control->echoMode();
860     if (echo == QSGTextInput::Password || echo == QSGTextInput::NoEcho)
861         hints |= Qt::ImhHiddenText;
862     else if (echo == QSGTextInput::PasswordEchoOnEdit)
863         hints &= ~Qt::ImhHiddenText;
864     if (echo != QSGTextInput::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 QSGTextInput::EchoMode QSGTextInput::echoMode() const
881 {
882     Q_D(const QSGTextInput);
883     return (QSGTextInput::EchoMode)d->control->echoMode();
884 }
885
886 void QSGTextInput::setEchoMode(QSGTextInput::EchoMode echo)
887 {
888     Q_D(QSGTextInput);
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 QSGTextInput::imHints() const
898 {
899     Q_D(const QSGTextInput);
900     return d->inputMethodHints;
901 }
902
903 void QSGTextInput::setIMHints(Qt::InputMethodHints hints)
904 {
905     Q_D(QSGTextInput);
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* QSGTextInput::cursorDelegate() const
926 {
927     Q_D(const QSGTextInput);
928     return d->cursorComponent;
929 }
930
931 void QSGTextInput::setCursorDelegate(QDeclarativeComponent* c)
932 {
933     Q_D(QSGTextInput);
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 QSGTextInputPrivate::startCreatingCursor()
949 {
950     Q_Q(QSGTextInput);
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()) << QSGTextInput::tr("Could not load cursor delegate");
958     }
959 }
960
961 void QSGTextInput::createCursor()
962 {
963     Q_D(QSGTextInput);
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     d->cursorItem = qobject_cast<QSGItem*>(d->cursorComponent->create());
975     if(!d->cursorItem){
976         qmlInfo(this, d->cursorComponent->errors()) << tr("Could not instantiate cursor delegate");
977         return;
978     }
979
980     QDeclarative_setParent_noEvent(d->cursorItem, this);
981     d->cursorItem->setParentItem(this);
982     d->cursorItem->setX(d->control->cursorToX());
983     d->cursorItem->setHeight(d->control->height()-1); // -1 to counter QLineControl's +1 which is not consistent with Text.
984 }
985
986 /*!
987     \qmlmethod rect QtQuick2::TextInput::positionToRectangle(int pos)
988
989     This function takes a character position and returns the rectangle that the
990     cursor would occupy, if it was placed at that character position.
991
992     This is similar to setting the cursorPosition, and then querying the cursor
993     rectangle, but the cursorPosition is not changed.
994 */
995 QRectF QSGTextInput::positionToRectangle(int pos) const
996 {
997     Q_D(const QSGTextInput);
998     if (pos > d->control->cursorPosition())
999         pos += d->control->preeditAreaText().length();
1000     return QRectF(d->control->cursorToX(pos)-d->hscroll,
1001         0.0,
1002         d->control->cursorWidth(),
1003         cursorRectangle().height());
1004 }
1005
1006 /*!
1007     \qmlmethod int QtQuick2::TextInput::positionAt(int x, CursorPosition position = CursorBetweenCharacters)
1008
1009     This function returns the character position at
1010     x pixels from the left of the textInput. Position 0 is before the
1011     first character, position 1 is after the first character but before the second,
1012     and so on until position text.length, which is after all characters.
1013
1014     This means that for all x values before the first character this function returns 0,
1015     and for all x values after the last character this function returns text.length.
1016
1017     The cursor position type specifies how the cursor position should be resolved.
1018
1019     \list
1020     \o TextInput.CursorBetweenCharacters - Returns the position between characters that is nearest x.
1021     \o TextInput.CursorOnCharacter - Returns the position before the character that is nearest x.
1022     \endlist
1023 */
1024 int QSGTextInput::positionAt(int x) const
1025 {
1026     return positionAt(x, CursorBetweenCharacters);
1027 }
1028
1029 int QSGTextInput::positionAt(int x, CursorPosition position) const
1030 {
1031     Q_D(const QSGTextInput);
1032     int pos = d->control->xToPos(x + d->hscroll, QTextLine::CursorPosition(position));
1033     const int cursor = d->control->cursor();
1034     if (pos > cursor) {
1035         const int preeditLength = d->control->preeditAreaText().length();
1036         pos = pos > cursor + preeditLength
1037                 ? pos - preeditLength
1038                 : cursor;
1039     }
1040     return pos;
1041 }
1042
1043 void QSGTextInput::keyPressEvent(QKeyEvent* ev)
1044 {
1045     Q_D(QSGTextInput);
1046     // Don't allow MacOSX up/down support, and we don't allow a completer.
1047     bool ignore = (ev->key() == Qt::Key_Up || ev->key() == Qt::Key_Down) && ev->modifiers() == Qt::NoModifier;
1048     if (!ignore && (d->lastSelectionStart == d->lastSelectionEnd) && (ev->key() == Qt::Key_Right || ev->key() == Qt::Key_Left)) {
1049         // Ignore when moving off the end unless there is a selection,
1050         // because then moving will do something (deselect).
1051         int cursorPosition = d->control->cursor();
1052         if (cursorPosition == 0)
1053             ignore = ev->key() == (d->control->layoutDirection() == Qt::LeftToRight ? Qt::Key_Left : Qt::Key_Right);
1054         if (cursorPosition == d->control->text().length())
1055             ignore = ev->key() == (d->control->layoutDirection() == Qt::LeftToRight ? Qt::Key_Right : Qt::Key_Left);
1056     }
1057     if (ignore) {
1058         ev->ignore();
1059     } else {
1060         d->control->processKeyEvent(ev);
1061     }
1062     if (!ev->isAccepted())
1063         QSGImplicitSizeItem::keyPressEvent(ev);
1064 }
1065
1066 void QSGTextInput::inputMethodEvent(QInputMethodEvent *ev)
1067 {
1068     Q_D(QSGTextInput);
1069     const bool wasComposing = d->control->preeditAreaText().length() > 0;
1070     if (d->control->isReadOnly()) {
1071         ev->ignore();
1072     } else {
1073         d->control->processInputMethodEvent(ev);
1074     }
1075     if (!ev->isAccepted())
1076         QSGImplicitSizeItem::inputMethodEvent(ev);
1077
1078     if (wasComposing != (d->control->preeditAreaText().length() > 0))
1079         emit inputMethodComposingChanged();
1080 }
1081
1082 void QSGTextInput::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
1083 {
1084     Q_D(QSGTextInput);
1085     if (d->sendMouseEventToInputContext(event, QEvent::MouseButtonDblClick))
1086         return;
1087     if (d->selectByMouse) {
1088         int cursor = d->xToPos(event->pos().x());
1089         d->control->selectWordAtPos(cursor);
1090         event->setAccepted(true);
1091     } else {
1092         QSGImplicitSizeItem::mouseDoubleClickEvent(event);
1093     }
1094 }
1095
1096 void QSGTextInput::mousePressEvent(QGraphicsSceneMouseEvent *event)
1097 {
1098     Q_D(QSGTextInput);
1099     if (d->sendMouseEventToInputContext(event, QEvent::MouseButtonPress))
1100         return;
1101     if(d->focusOnPress){
1102         bool hadActiveFocus = hasActiveFocus();
1103         forceActiveFocus();
1104         if (d->showInputPanelOnFocus) {
1105             if (hasActiveFocus() && hadActiveFocus && !isReadOnly()) {
1106                 // re-open input panel on press if already focused
1107                 openSoftwareInputPanel();
1108             }
1109         } else { // show input panel on click
1110             if (hasActiveFocus() && !hadActiveFocus) {
1111                 d->clickCausedFocus = true;
1112             }
1113         }
1114     }
1115     if (d->selectByMouse) {
1116         setKeepMouseGrab(false);
1117         d->selectPressed = true;
1118         d->pressPos = event->pos();
1119     }
1120     bool mark = (event->modifiers() & Qt::ShiftModifier) && d->selectByMouse;
1121     int cursor = d->xToPos(event->pos().x());
1122     d->control->moveCursor(cursor, mark);
1123     event->setAccepted(true);
1124 }
1125
1126 void QSGTextInput::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
1127 {
1128     Q_D(QSGTextInput);
1129     if (d->sendMouseEventToInputContext(event, QEvent::MouseMove))
1130         return;
1131     if (d->selectPressed) {
1132         if (qAbs(int(event->pos().x() - d->pressPos.x())) > QApplication::startDragDistance())
1133             setKeepMouseGrab(true);
1134         moveCursorSelection(d->xToPos(event->pos().x()), d->mouseSelectionMode);
1135         event->setAccepted(true);
1136     } else {
1137         QSGImplicitSizeItem::mouseMoveEvent(event);
1138     }
1139 }
1140
1141 void QSGTextInput::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
1142 {
1143     Q_D(QSGTextInput);
1144     if (d->sendMouseEventToInputContext(event, QEvent::MouseButtonRelease))
1145         return;
1146     if (d->selectPressed) {
1147         d->selectPressed = false;
1148         setKeepMouseGrab(false);
1149     }
1150     if (!d->showInputPanelOnFocus) { // input panel on click
1151         if (d->focusOnPress && !isReadOnly() && boundingRect().contains(event->pos())) {
1152             if (canvas() && canvas() == QGuiApplication::activeWindow()) {
1153                 // ### refactor: implement virtual keyboard properly..
1154                 qDebug("QSGTextInput: virtual keyboard no implemented...");
1155 //                qt_widget_private(canvas())->handleSoftwareInputPanel(event->button(), d->clickCausedFocus);
1156             }
1157         }
1158     }
1159     d->clickCausedFocus = false;
1160     d->control->processEvent(event);
1161     if (!event->isAccepted())
1162         QSGImplicitSizeItem::mouseReleaseEvent(event);
1163 }
1164
1165 bool QSGTextInputPrivate::sendMouseEventToInputContext(
1166         QGraphicsSceneMouseEvent *event, QEvent::Type eventType)
1167 {
1168 #if !defined QT_NO_IM
1169     if (event->widget() && control->composeMode()) {
1170         int tmp_cursor = xToPos(event->pos().x());
1171         int mousePos = tmp_cursor - control->cursor();
1172         if (mousePos < 0 || mousePos > control->preeditAreaText().length()) {
1173             mousePos = -1;
1174             // don't send move events outside the preedit area
1175             if (eventType == QEvent::MouseMove)
1176                 return true;
1177         }
1178
1179         QInputContext *qic = event->widget()->inputContext();
1180         if (qic) {
1181             QMouseEvent mouseEvent(
1182                     eventType,
1183                     event->widget()->mapFromGlobal(event->screenPos()),
1184                     event->screenPos(),
1185                     event->button(),
1186                     event->buttons(),
1187                     event->modifiers());
1188             // may be causing reset() in some input methods
1189             qic->mouseHandler(mousePos, &mouseEvent);
1190             event->setAccepted(mouseEvent.isAccepted());
1191         }
1192         if (!control->preeditAreaText().isEmpty())
1193             return true;
1194     }
1195 #else
1196     Q_UNUSED(event);
1197     Q_UNUSED(eventType)
1198 #endif
1199
1200     return false;
1201 }
1202
1203 void QSGTextInput::mouseUngrabEvent()
1204 {
1205     Q_D(QSGTextInput);
1206     d->selectPressed = false;
1207     setKeepMouseGrab(false);
1208 }
1209
1210 bool QSGTextInput::event(QEvent* ev)
1211 {
1212     Q_D(QSGTextInput);
1213     //Anything we don't deal with ourselves, pass to the control
1214     bool handled = false;
1215     switch(ev->type()){
1216         case QEvent::KeyPress:
1217         case QEvent::KeyRelease://###Should the control be doing anything with release?
1218         case QEvent::InputMethod:
1219         case QEvent::GraphicsSceneMousePress:
1220         case QEvent::GraphicsSceneMouseMove:
1221         case QEvent::GraphicsSceneMouseRelease:
1222         case QEvent::GraphicsSceneMouseDoubleClick:
1223             break;
1224         default:
1225             handled = d->control->processEvent(ev);
1226     }
1227     if(!handled)
1228         handled = QSGImplicitSizeItem::event(ev);
1229     return handled;
1230 }
1231
1232 void QSGTextInput::geometryChanged(const QRectF &newGeometry,
1233                                   const QRectF &oldGeometry)
1234 {
1235     if (newGeometry.width() != oldGeometry.width()) {
1236         updateSize();
1237         updateCursorRectangle();
1238     }
1239     QSGImplicitSizeItem::geometryChanged(newGeometry, oldGeometry);
1240 }
1241
1242 int QSGTextInputPrivate::calculateTextWidth()
1243 {
1244     return qRound(control->naturalTextWidth());
1245 }
1246
1247 void QSGTextInputPrivate::updateHorizontalScroll()
1248 {
1249     Q_Q(QSGTextInput);
1250     const int preeditLength = control->preeditAreaText().length();
1251     const int width = q->width();
1252     int widthUsed = calculateTextWidth();
1253
1254     if (!autoScroll || widthUsed <=  width) {
1255         QSGTextInput::HAlignment effectiveHAlign = q->effectiveHAlign();
1256         // text fits in br; use hscroll for alignment
1257         switch (effectiveHAlign & ~(Qt::AlignAbsolute|Qt::AlignVertical_Mask)) {
1258         case Qt::AlignRight:
1259             hscroll = widthUsed - width;
1260             break;
1261         case Qt::AlignHCenter:
1262             hscroll = (widthUsed - width) / 2;
1263             break;
1264         default:
1265             // Left
1266             hscroll = 0;
1267             break;
1268         }
1269     } else {
1270         int cix = qRound(control->cursorToX(control->cursor() + preeditLength));
1271         if (cix - hscroll >= width) {
1272             // text doesn't fit, cursor is to the right of br (scroll right)
1273             hscroll = cix - width;
1274         } else if (cix - hscroll < 0 && hscroll < widthUsed) {
1275             // text doesn't fit, cursor is to the left of br (scroll left)
1276             hscroll = cix;
1277         } else if (widthUsed - hscroll < width) {
1278             // text doesn't fit, text document is to the left of br; align
1279             // right
1280             hscroll = widthUsed - width;
1281         }
1282         if (preeditLength > 0) {
1283             // check to ensure long pre-edit text doesn't push the cursor
1284             // off to the left
1285              cix = qRound(control->cursorToX(
1286                      control->cursor() + qMax(0, control->preeditCursor() - 1)));
1287              if (cix < hscroll)
1288                  hscroll = cix;
1289         }
1290     }
1291 }
1292
1293 QSGNode *QSGTextInput::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
1294 {
1295     Q_UNUSED(data);
1296     Q_D(QSGTextInput);
1297
1298     QSGTextNode *node = static_cast<QSGTextNode *>(oldNode);
1299     if (node == 0)
1300         node = new QSGTextNode(QSGItemPrivate::get(this)->sceneGraphContext());
1301     d->textNode = node;
1302
1303     if (!d->textLayoutDirty) {
1304         QSGSimpleRectNode *cursorNode = node->cursorNode();
1305         if (cursorNode != 0 && !isReadOnly()) {
1306             QFontMetrics fm = QFontMetrics(d->font);
1307             // the y offset is there to keep the baseline constant in case we have script changes in the text.
1308             QPoint offset(-d->hscroll, fm.ascent() - d->control->ascent());
1309             offset.rx() += d->control->cursorToX();
1310
1311             QRect br(boundingRect().toRect());
1312             cursorNode->setRect(QRectF(offset, QSizeF(d->control->cursorWidth(), br.height())));
1313
1314             if (!d->cursorVisible
1315                     || (!d->control->cursorBlinkStatus() && d->control->cursorBlinkPeriod() > 0)) {
1316                 d->hideCursor();
1317             } else {
1318                 d->showCursor();
1319             }
1320         }
1321     } else {
1322         node->deleteContent();
1323         node->setMatrix(QMatrix4x4());
1324
1325         QPoint offset = QPoint(0,0);
1326         QFontMetrics fm = QFontMetrics(d->font);
1327         QRect br(boundingRect().toRect());
1328         if (d->autoScroll) {
1329             // the y offset is there to keep the baseline constant in case we have script changes in the text.
1330             offset = br.topLeft() - QPoint(d->hscroll, d->control->ascent() - fm.ascent());
1331         } else {
1332             offset = QPoint(d->hscroll, 0);
1333         }
1334
1335         QTextLayout *textLayout = d->control->textLayout();
1336         if (!textLayout->text().isEmpty()) {
1337             node->addTextLayout(offset, textLayout, d->color,
1338                                 QSGText::Normal, QColor(),
1339                                 d->selectionColor, d->selectedTextColor,
1340                                 d->control->selectionStart(),
1341                                 d->control->selectionEnd() - 1); // selectionEnd() returns first char after
1342                                                                  // selection
1343         }
1344
1345         if (!isReadOnly() && d->cursorItem == 0) {
1346             offset.rx() += d->control->cursorToX();
1347             node->setCursor(QRectF(offset, QSizeF(d->control->cursorWidth(), br.height())), d->color);
1348             if (!d->cursorVisible
1349                     || (!d->control->cursorBlinkStatus() && d->control->cursorBlinkPeriod() > 0)) {
1350                 d->hideCursor();
1351             } else {
1352                 d->showCursor();
1353             }
1354         }
1355
1356         d->textLayoutDirty = false;
1357     }
1358
1359     return node;
1360 }
1361
1362 QVariant QSGTextInput::inputMethodQuery(Qt::InputMethodQuery property) const
1363 {
1364     Q_D(const QSGTextInput);
1365     switch(property) {
1366     case Qt::ImMicroFocus:
1367         return cursorRectangle();
1368     case Qt::ImFont:
1369         return font();
1370     case Qt::ImCursorPosition:
1371         return QVariant(d->control->cursor());
1372     case Qt::ImSurroundingText:
1373         if (d->control->echoMode() == PasswordEchoOnEdit && !d->control->passwordEchoEditing())
1374             return QVariant(displayText());
1375         else
1376             return QVariant(text());
1377     case Qt::ImCurrentSelection:
1378         return QVariant(selectedText());
1379     case Qt::ImMaximumTextLength:
1380         return QVariant(maxLength());
1381     case Qt::ImAnchorPosition:
1382         if (d->control->selectionStart() == d->control->selectionEnd())
1383             return QVariant(d->control->cursor());
1384         else if (d->control->selectionStart() == d->control->cursor())
1385             return QVariant(d->control->selectionEnd());
1386         else
1387             return QVariant(d->control->selectionStart());
1388     default:
1389         return QVariant();
1390     }
1391 }
1392
1393 /*!
1394     \qmlmethod void QtQuick2::TextInput::deselect()
1395
1396     Removes active text selection.
1397 */
1398 void QSGTextInput::deselect()
1399 {
1400     Q_D(QSGTextInput);
1401     d->control->deselect();
1402 }
1403
1404 /*!
1405     \qmlmethod void QtQuick2::TextInput::selectAll()
1406
1407     Causes all text to be selected.
1408 */
1409 void QSGTextInput::selectAll()
1410 {
1411     Q_D(QSGTextInput);
1412     d->control->setSelection(0, d->control->text().length());
1413 }
1414
1415 /*!
1416     \qmlmethod void QtQuick2::TextInput::isRightToLeft(int start, int end)
1417
1418     Returns true if the natural reading direction of the editor text
1419     found between positions \a start and \a end is right to left.
1420 */
1421 bool QSGTextInput::isRightToLeft(int start, int end)
1422 {
1423     Q_D(QSGTextInput);
1424     if (start > end) {
1425         qmlInfo(this) << "isRightToLeft(start, end) called with the end property being smaller than the start.";
1426         return false;
1427     } else {
1428         return d->control->text().mid(start, end - start).isRightToLeft();
1429     }
1430 }
1431
1432 #ifndef QT_NO_CLIPBOARD
1433 /*!
1434     \qmlmethod QtQuick2::TextInput::cut()
1435
1436     Moves the currently selected text to the system clipboard.
1437 */
1438 void QSGTextInput::cut()
1439 {
1440     Q_D(QSGTextInput);
1441     d->control->copy();
1442     d->control->del();
1443 }
1444
1445 /*!
1446     \qmlmethod QtQuick2::TextInput::copy()
1447
1448     Copies the currently selected text to the system clipboard.
1449 */
1450 void QSGTextInput::copy()
1451 {
1452     Q_D(QSGTextInput);
1453     d->control->copy();
1454 }
1455
1456 /*!
1457     \qmlmethod QtQuick2::TextInput::paste()
1458
1459     Replaces the currently selected text by the contents of the system clipboard.
1460 */
1461 void QSGTextInput::paste()
1462 {
1463     Q_D(QSGTextInput);
1464     if (!d->control->isReadOnly())
1465         d->control->paste();
1466 }
1467 #endif // QT_NO_CLIPBOARD
1468
1469 /*!
1470     \qmlmethod void QtQuick2::TextInput::selectWord()
1471
1472     Causes the word closest to the current cursor position to be selected.
1473 */
1474 void QSGTextInput::selectWord()
1475 {
1476     Q_D(QSGTextInput);
1477     d->control->selectWordAtPos(d->control->cursor());
1478 }
1479
1480 /*!
1481     \qmlproperty bool QtQuick2::TextInput::smooth
1482
1483     This property holds whether the text is smoothly scaled or transformed.
1484
1485     Smooth filtering gives better visual quality, but is slower.  If
1486     the item is displayed at its natural size, this property has no visual or
1487     performance effect.
1488
1489     \note Generally scaling artifacts are only visible if the item is stationary on
1490     the screen.  A common pattern when animating an item is to disable smooth
1491     filtering at the beginning of the animation and reenable it at the conclusion.
1492 */
1493
1494 /*!
1495    \qmlproperty string QtQuick2::TextInput::passwordCharacter
1496
1497    This is the character displayed when echoMode is set to Password or
1498    PasswordEchoOnEdit. By default it is an asterisk.
1499
1500    If this property is set to a string with more than one character,
1501    the first character is used. If the string is empty, the value
1502    is ignored and the property is not set.
1503 */
1504 QString QSGTextInput::passwordCharacter() const
1505 {
1506     Q_D(const QSGTextInput);
1507     return QString(d->control->passwordCharacter());
1508 }
1509
1510 void QSGTextInput::setPasswordCharacter(const QString &str)
1511 {
1512     Q_D(QSGTextInput);
1513     if(str.length() < 1)
1514         return;
1515     d->control->setPasswordCharacter(str.constData()[0]);
1516     EchoMode echoMode_ = echoMode();
1517     if (echoMode_ == Password || echoMode_ == PasswordEchoOnEdit) {
1518         updateSize();
1519     }
1520     emit passwordCharacterChanged();
1521 }
1522
1523 /*!
1524    \qmlproperty string QtQuick2::TextInput::displayText
1525
1526    This is the text displayed in the TextInput.
1527
1528    If \l echoMode is set to TextInput::Normal, this holds the
1529    same value as the TextInput::text property. Otherwise,
1530    this property holds the text visible to the user, while
1531    the \l text property holds the actual entered text.
1532 */
1533 QString QSGTextInput::displayText() const
1534 {
1535     Q_D(const QSGTextInput);
1536     return d->control->displayText();
1537 }
1538
1539 /*!
1540     \qmlproperty bool QtQuick2::TextInput::selectByMouse
1541
1542     Defaults to false.
1543
1544     If true, the user can use the mouse to select text in some
1545     platform-specific way. Note that for some platforms this may
1546     not be an appropriate interaction (eg. may conflict with how
1547     the text needs to behave inside a Flickable.
1548 */
1549 bool QSGTextInput::selectByMouse() const
1550 {
1551     Q_D(const QSGTextInput);
1552     return d->selectByMouse;
1553 }
1554
1555 void QSGTextInput::setSelectByMouse(bool on)
1556 {
1557     Q_D(QSGTextInput);
1558     if (d->selectByMouse != on) {
1559         d->selectByMouse = on;
1560         emit selectByMouseChanged(on);
1561     }
1562 }
1563
1564 /*!
1565     \qmlproperty enum QtQuick2::TextInput::mouseSelectionMode
1566
1567     Specifies how text should be selected using a mouse.
1568
1569     \list
1570     \o TextInput.SelectCharacters - The selection is updated with individual characters. (Default)
1571     \o TextInput.SelectWords - The selection is updated with whole words.
1572     \endlist
1573
1574     This property only applies when \l selectByMouse is true.
1575 */
1576
1577 QSGTextInput::SelectionMode QSGTextInput::mouseSelectionMode() const
1578 {
1579     Q_D(const QSGTextInput);
1580     return d->mouseSelectionMode;
1581 }
1582
1583 void QSGTextInput::setMouseSelectionMode(SelectionMode mode)
1584 {
1585     Q_D(QSGTextInput);
1586     if (d->mouseSelectionMode != mode) {
1587         d->mouseSelectionMode = mode;
1588         emit mouseSelectionModeChanged(mode);
1589     }
1590 }
1591
1592 /*!
1593     \qmlproperty bool QtQuick2::TextInput::canPaste
1594
1595     Returns true if the TextInput is writable and the content of the clipboard is
1596     suitable for pasting into the TextEdit.
1597 */
1598 bool QSGTextInput::canPaste() const
1599 {
1600     Q_D(const QSGTextInput);
1601     return d->canPaste;
1602 }
1603
1604 void QSGTextInput::moveCursorSelection(int position)
1605 {
1606     Q_D(QSGTextInput);
1607     d->control->moveCursor(position, true);
1608 }
1609
1610 /*!
1611     \qmlmethod void QtQuick2::TextInput::moveCursorSelection(int position, SelectionMode mode = TextInput.SelectCharacters)
1612
1613     Moves the cursor to \a position and updates the selection according to the optional \a mode
1614     parameter.  (To only move the cursor, set the \l cursorPosition property.)
1615
1616     When this method is called it additionally sets either the
1617     selectionStart or the selectionEnd (whichever was at the previous cursor position)
1618     to the specified position. This allows you to easily extend and contract the selected
1619     text range.
1620
1621     The selection mode specifies whether the selection is updated on a per character or a per word
1622     basis.  If not specified the selection mode will default to TextInput.SelectCharacters.
1623
1624     \list
1625     \o TextEdit.SelectCharacters - Sets either the selectionStart or selectionEnd (whichever was at
1626     the previous cursor position) to the specified position.
1627     \o TextEdit.SelectWords - Sets the selectionStart and selectionEnd to include all
1628     words between the specified postion and the previous cursor position.  Words partially in the
1629     range are included.
1630     \endlist
1631
1632     For example, take this sequence of calls:
1633
1634     \code
1635         cursorPosition = 5
1636         moveCursorSelection(9, TextInput.SelectCharacters)
1637         moveCursorSelection(7, TextInput.SelectCharacters)
1638     \endcode
1639
1640     This moves the cursor to position 5, extend the selection end from 5 to 9
1641     and then retract the selection end from 9 to 7, leaving the text from position 5 to 7
1642     selected (the 6th and 7th characters).
1643
1644     The same sequence with TextInput.SelectWords will extend the selection start to a word boundary
1645     before or on position 5 and extend the selection end to a word boundary on or past position 9.
1646 */
1647 void QSGTextInput::moveCursorSelection(int pos, SelectionMode mode)
1648 {
1649     Q_D(QSGTextInput);
1650
1651     if (mode == SelectCharacters) {
1652         d->control->moveCursor(pos, true);
1653     } else if (pos != d->control->cursor()){
1654         const int cursor = d->control->cursor();
1655         int anchor;
1656         if (!d->control->hasSelectedText())
1657             anchor = d->control->cursor();
1658         else if (d->control->selectionStart() == d->control->cursor())
1659             anchor = d->control->selectionEnd();
1660         else
1661             anchor = d->control->selectionStart();
1662
1663         if (anchor < pos || (anchor == pos && cursor < pos)) {
1664             const QString text = d->control->text();
1665             QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
1666             finder.setPosition(anchor);
1667
1668             const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
1669             if (anchor < text.length() && (!(reasons & QTextBoundaryFinder::StartWord)
1670                     || ((reasons & QTextBoundaryFinder::EndWord) && anchor > cursor))) {
1671                 finder.toPreviousBoundary();
1672             }
1673             anchor = finder.position() != -1 ? finder.position() : 0;
1674
1675             finder.setPosition(pos);
1676             if (pos > 0 && !finder.boundaryReasons())
1677                 finder.toNextBoundary();
1678             const int cursor = finder.position() != -1 ? finder.position() : text.length();
1679
1680             d->control->setSelection(anchor, cursor - anchor);
1681         } else if (anchor > pos || (anchor == pos && cursor > pos)) {
1682             const QString text = d->control->text();
1683             QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
1684             finder.setPosition(anchor);
1685
1686             const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
1687             if (anchor > 0 && (!(reasons & QTextBoundaryFinder::EndWord)
1688                     || ((reasons & QTextBoundaryFinder::StartWord) && anchor < cursor))) {
1689                 finder.toNextBoundary();
1690             }
1691
1692             anchor = finder.position() != -1 ? finder.position() : text.length();
1693
1694             finder.setPosition(pos);
1695             if (pos < text.length() && !finder.boundaryReasons())
1696                  finder.toPreviousBoundary();
1697             const int cursor = finder.position() != -1 ? finder.position() : 0;
1698
1699             d->control->setSelection(anchor, cursor - anchor);
1700         }
1701     }
1702 }
1703
1704 /*!
1705     \qmlmethod void QtQuick2::TextInput::openSoftwareInputPanel()
1706
1707     Opens software input panels like virtual keyboards for typing, useful for
1708     customizing when you want the input keyboard to be shown and hidden in
1709     your application.
1710
1711     By default the opening of input panels follows the platform style. On Symbian^1 and
1712     Symbian^3 -based devices the panels are opened by clicking TextInput. On other platforms
1713     the panels are automatically opened when TextInput element gains active focus. Input panels are
1714     always closed if no editor has active focus.
1715
1716   . You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
1717     and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
1718     the behavior you want.
1719
1720     Only relevant on platforms, which provide virtual keyboards.
1721
1722     \qml
1723         import QtQuick 1.0
1724         TextInput {
1725             id: textInput
1726             text: "Hello world!"
1727             activeFocusOnPress: false
1728             MouseArea {
1729                 anchors.fill: parent
1730                 onClicked: {
1731                     if (!textInput.activeFocus) {
1732                         textInput.forceActiveFocus()
1733                         textInput.openSoftwareInputPanel();
1734                     } else {
1735                         textInput.focus = false;
1736                     }
1737                 }
1738                 onPressAndHold: textInput.closeSoftwareInputPanel();
1739             }
1740         }
1741     \endqml
1742 */
1743 void QSGTextInput::openSoftwareInputPanel()
1744 {
1745     if (qApp) {
1746         if (canvas()) {
1747             QEvent event(QEvent::RequestSoftwareInputPanel);
1748             QApplication::sendEvent(canvas(), &event);
1749         }
1750     }
1751 }
1752
1753 /*!
1754     \qmlmethod void QtQuick2::TextInput::closeSoftwareInputPanel()
1755
1756     Closes a software input panel like a virtual keyboard shown on the screen, useful
1757     for customizing when you want the input keyboard to be shown and hidden in
1758     your application.
1759
1760     By default the opening of input panels follows the platform style. On Symbian^1 and
1761     Symbian^3 -based devices the panels are opened by clicking TextInput. On other platforms
1762     the panels are automatically opened when TextInput element gains active focus. Input panels are
1763     always closed if no editor has active focus.
1764
1765   . You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
1766     and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
1767     the behavior you want.
1768
1769     Only relevant on platforms, which provide virtual keyboards.
1770
1771     \qml
1772         import QtQuick 1.0
1773         TextInput {
1774             id: textInput
1775             text: "Hello world!"
1776             activeFocusOnPress: false
1777             MouseArea {
1778                 anchors.fill: parent
1779                 onClicked: {
1780                     if (!textInput.activeFocus) {
1781                         textInput.forceActiveFocus();
1782                         textInput.openSoftwareInputPanel();
1783                     } else {
1784                         textInput.focus = false;
1785                     }
1786                 }
1787                 onPressAndHold: textInput.closeSoftwareInputPanel();
1788             }
1789         }
1790     \endqml
1791 */
1792 void QSGTextInput::closeSoftwareInputPanel()
1793 {
1794     if (qApp) {
1795         if (canvas()) {
1796             QEvent event(QEvent::CloseSoftwareInputPanel);
1797             QApplication::sendEvent(canvas(), &event);
1798         }
1799     }
1800 }
1801
1802 void QSGTextInput::focusInEvent(QFocusEvent *event)
1803 {
1804     Q_D(const QSGTextInput);
1805     if (d->showInputPanelOnFocus) {
1806         if (d->focusOnPress && !isReadOnly()) {
1807             openSoftwareInputPanel();
1808         }
1809     }
1810     QSGImplicitSizeItem::focusInEvent(event);
1811 }
1812
1813 void QSGTextInput::itemChange(ItemChange change, const ItemChangeData &value)
1814 {
1815     Q_D(QSGTextInput);
1816     if (change == ItemActiveFocusHasChanged) {
1817         bool hasFocus = value.boolValue;
1818         d->focused = hasFocus;
1819         setCursorVisible(hasFocus); // ### refactor:  && d->canvas && d->canvas->hasFocus()
1820         if(echoMode() == QSGTextInput::PasswordEchoOnEdit && !hasFocus)
1821             d->control->updatePasswordEchoEditing(false);//QLineControl sets it on key events, but doesn't deal with focus events
1822         if (!hasFocus)
1823             d->control->deselect();
1824     }
1825     QSGItem::itemChange(change, value);
1826 }
1827
1828 /*!
1829     \qmlproperty bool QtQuick2::TextInput::inputMethodComposing
1830
1831
1832     This property holds whether the TextInput has partial text input from an
1833     input method.
1834
1835     While it is composing an input method may rely on mouse or key events from
1836     the TextInput to edit or commit the partial text.  This property can be
1837     used to determine when to disable events handlers that may interfere with
1838     the correct operation of an input method.
1839 */
1840 bool QSGTextInput::isInputMethodComposing() const
1841 {
1842     Q_D(const QSGTextInput);
1843     return d->control->preeditAreaText().length() > 0;
1844 }
1845
1846 void QSGTextInputPrivate::init()
1847 {
1848     Q_Q(QSGTextInput);
1849 #if defined(Q_WS_MAC)
1850     control->setThreadChecks(true);
1851 #endif
1852     control->setParent(q);//Now mandatory due to accessibility changes
1853     control->setCursorWidth(1);
1854     control->setPasswordCharacter(QLatin1Char('*'));
1855     q->setSmooth(smooth);
1856     q->setAcceptedMouseButtons(Qt::LeftButton);
1857     q->setFlag(QSGItem::ItemAcceptsInputMethod);
1858     q->setFlag(QSGItem::ItemHasContents);
1859     q->connect(control, SIGNAL(cursorPositionChanged(int,int)),
1860                q, SLOT(cursorPosChanged()));
1861     q->connect(control, SIGNAL(selectionChanged()),
1862                q, SLOT(selectionChanged()));
1863     q->connect(control, SIGNAL(textChanged(QString)),
1864                q, SLOT(q_textChanged()));
1865     q->connect(control, SIGNAL(accepted()),
1866                q, SIGNAL(accepted()));
1867     q->connect(control, SIGNAL(updateNeeded(QRect)),
1868                q, SLOT(updateRect(QRect)));
1869 #ifndef QT_NO_CLIPBOARD
1870     q->connect(q, SIGNAL(readOnlyChanged(bool)),
1871             q, SLOT(q_canPasteChanged()));
1872     q->connect(QApplication::clipboard(), SIGNAL(dataChanged()),
1873             q, SLOT(q_canPasteChanged()));
1874     canPaste = !control->isReadOnly() && QApplication::clipboard()->text().length() != 0;
1875 #endif // QT_NO_CLIPBOARD
1876     q->connect(control, SIGNAL(updateMicroFocus()),
1877                q, SLOT(updateCursorRectangle()));
1878     q->connect(control, SIGNAL(displayTextChanged(QString)),
1879                q, SLOT(updateRect()));
1880     q->updateSize();
1881     oldValidity = control->hasAcceptableInput();
1882     lastSelectionStart = 0;
1883     lastSelectionEnd = 0;
1884     QPalette p = control->palette();
1885     selectedTextColor = p.color(QPalette::HighlightedText);
1886     selectionColor = p.color(QPalette::Highlight);
1887     determineHorizontalAlignment();
1888
1889     if (!qmlDisableDistanceField()) {
1890         QTextOption option = control->textLayout()->textOption();
1891         option.setUseDesignMetrics(true);
1892         control->textLayout()->setTextOption(option);
1893     }
1894 }
1895
1896 void QSGTextInput::cursorPosChanged()
1897 {
1898     Q_D(QSGTextInput);
1899     updateCursorRectangle();
1900     emit cursorPositionChanged();
1901     // XXX todo - not in 4.8?
1902 #if 0
1903     d->control->resetCursorBlinkTimer();
1904 #endif
1905
1906     if(!d->control->hasSelectedText()){
1907         if(d->lastSelectionStart != d->control->cursor()){
1908             d->lastSelectionStart = d->control->cursor();
1909             emit selectionStartChanged();
1910         }
1911         if(d->lastSelectionEnd != d->control->cursor()){
1912             d->lastSelectionEnd = d->control->cursor();
1913             emit selectionEndChanged();
1914         }
1915     }
1916 }
1917
1918 void QSGTextInput::updateCursorRectangle()
1919 {
1920     Q_D(QSGTextInput);
1921     d->updateHorizontalScroll();
1922     updateRect();//TODO: Only update rect between pos's
1923     updateMicroFocus();
1924     emit cursorRectangleChanged();
1925     if (d->cursorItem)
1926         d->cursorItem->setX(d->control->cursorToX() - d->hscroll);
1927 }
1928
1929 void QSGTextInput::selectionChanged()
1930 {
1931     Q_D(QSGTextInput);
1932     updateRect();//TODO: Only update rect in selection
1933     emit selectedTextChanged();
1934
1935     if(d->lastSelectionStart != d->control->selectionStart()){
1936         d->lastSelectionStart = d->control->selectionStart();
1937         if(d->lastSelectionStart == -1)
1938             d->lastSelectionStart = d->control->cursor();
1939         emit selectionStartChanged();
1940     }
1941     if(d->lastSelectionEnd != d->control->selectionEnd()){
1942         d->lastSelectionEnd = d->control->selectionEnd();
1943         if(d->lastSelectionEnd == -1)
1944             d->lastSelectionEnd = d->control->cursor();
1945         emit selectionEndChanged();
1946     }
1947 }
1948
1949 void QSGTextInput::q_textChanged()
1950 {
1951     Q_D(QSGTextInput);
1952     emit textChanged();
1953     emit displayTextChanged();
1954     updateSize();
1955     d->determineHorizontalAlignment();
1956     d->updateHorizontalScroll();
1957     updateMicroFocus();
1958     if(hasAcceptableInput() != d->oldValidity){
1959         d->oldValidity = hasAcceptableInput();
1960         emit acceptableInputChanged();
1961     }
1962 }
1963
1964 void QSGTextInputPrivate::showCursor()
1965 {
1966     if (textNode != 0 && textNode->cursorNode() != 0)
1967         textNode->cursorNode()->setColor(color);
1968 }
1969
1970 void QSGTextInputPrivate::hideCursor()
1971 {
1972     if (textNode != 0 && textNode->cursorNode() != 0)
1973         textNode->cursorNode()->setColor(QColor(0, 0, 0, 0));
1974 }
1975
1976 void QSGTextInput::updateRect(const QRect &r)
1977 {
1978     Q_D(QSGTextInput);
1979     if (!isComponentComplete())
1980         return;
1981
1982     if (r.isEmpty()) {
1983         d->textLayoutDirty = true;
1984     }
1985
1986     update();
1987 }
1988
1989 QRectF QSGTextInput::boundingRect() const
1990 {
1991     Q_D(const QSGTextInput);
1992     QRectF r = QSGImplicitSizeItem::boundingRect();
1993
1994     int cursorWidth = d->cursorItem ? d->cursorItem->width() : d->control->cursorWidth();
1995
1996     // Could include font max left/right bearings to either side of rectangle.
1997
1998     r.setRight(r.right() + cursorWidth);
1999     return r;
2000 }
2001
2002 void QSGTextInput::updateSize(bool needsRedraw)
2003 {
2004     Q_D(QSGTextInput);
2005     int w = width();
2006     int h = height();
2007     setImplicitHeight(d->control->height()-1); // -1 to counter QLineControl's +1 which is not consistent with Text.
2008     setImplicitWidth(d->calculateTextWidth());
2009     if(w==width() && h==height() && needsRedraw)
2010         update();
2011 }
2012
2013 void QSGTextInput::q_canPasteChanged()
2014 {
2015     Q_D(QSGTextInput);
2016     bool old = d->canPaste;
2017 #ifndef QT_NO_CLIPBOARD
2018     d->canPaste = !d->control->isReadOnly() && QApplication::clipboard()->text().length() != 0;
2019 #endif
2020     if(d->canPaste != old)
2021         emit canPasteChanged();
2022 }
2023
2024 QT_END_NAMESPACE
2025