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