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