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