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