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