Fix IM repaint.
[qt:kenya888s-qt-palm-pre.git] / src / declarative / graphicsitems / qdeclarativetextinput.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
14 ** this package.
15 **
16 ** GNU Lesser General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 ** General Public License version 2.1 as published by the Free Software
19 ** Foundation and appearing in the file LICENSE.LGPL included in the
20 ** packaging of this file.  Please review the following information to
21 ** ensure the GNU Lesser General Public License version 2.1 requirements
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23 **
24 ** In addition, as a special exception, Nokia gives you certain additional
25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27 **
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
30 **
31 **
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qdeclarativetextinput_p.h"
43 #include "qdeclarativetextinput_p_p.h"
44
45 #include <qdeclarativeinfo.h>
46
47 #include <QValidator>
48 #include <QApplication>
49 #include <QFontMetrics>
50 #include <QPainter>
51
52 QT_BEGIN_NAMESPACE
53
54 /*!
55     \qmlclass TextInput QDeclarativeTextInput
56   \since 4.7
57     The TextInput item allows you to add an editable line of text to a scene.
58
59     TextInput can only display a single line of text, and can only display
60     plain text. However it can provide addition input constraints on the text.
61
62     Input constraints include setting a QValidator, an input mask, or a
63     maximum input length.
64 */
65 QDeclarativeTextInput::QDeclarativeTextInput(QDeclarativeItem* parent)
66     : QDeclarativePaintedItem(*(new QDeclarativeTextInputPrivate), parent)
67 {
68     Q_D(QDeclarativeTextInput);
69     d->init();
70 }
71
72 QDeclarativeTextInput::~QDeclarativeTextInput()
73 {
74 }
75
76 /*!
77     \qmlproperty string TextInput::text
78
79     The text in the TextInput.
80 */
81
82 QString QDeclarativeTextInput::text() const
83 {
84     Q_D(const QDeclarativeTextInput);
85     return d->control->text();
86 }
87
88 void QDeclarativeTextInput::setText(const QString &s)
89 {
90     Q_D(QDeclarativeTextInput);
91     if(s == text())
92         return;
93     d->control->setText(s);
94     //emit textChanged();
95 }
96
97 /*!
98     \qmlproperty string TextInput::font.family
99     \qmlproperty bool TextInput::font.bold
100     \qmlproperty bool TextInput::font.italic
101     \qmlproperty bool TextInput::font.underline
102     \qmlproperty real TextInput::font.pointSize
103     \qmlproperty int TextInput::font.pixelSize
104
105     Set the TextInput's font attributes.
106 */
107 QFont QDeclarativeTextInput::font() const
108 {
109     Q_D(const QDeclarativeTextInput);
110     return d->font;
111 }
112
113 void QDeclarativeTextInput::setFont(const QFont &font)
114 {
115     Q_D(QDeclarativeTextInput);
116     if (d->font == font)
117         return;
118
119     d->font = font;
120
121     d->control->setFont(d->font);
122     if(d->cursorItem){
123         d->cursorItem->setHeight(QFontMetrics(d->font).height());
124         moveCursor();
125     }
126     updateSize();
127     emit fontChanged(d->font);
128 }
129
130 /*!
131     \qmlproperty color TextInput::color
132
133     The text color.
134 */
135 QColor QDeclarativeTextInput::color() const
136 {
137     Q_D(const QDeclarativeTextInput);
138     return d->color;
139 }
140
141 void QDeclarativeTextInput::setColor(const QColor &c)
142 {
143     Q_D(QDeclarativeTextInput);
144     d->color = c;
145 }
146
147
148 /*!
149     \qmlproperty color TextInput::selectionColor
150
151     The text highlight color, used behind selections.
152 */
153 QColor QDeclarativeTextInput::selectionColor() const
154 {
155     Q_D(const QDeclarativeTextInput);
156     return d->selectionColor;
157 }
158
159 void QDeclarativeTextInput::setSelectionColor(const QColor &color)
160 {
161     Q_D(QDeclarativeTextInput);
162     if (d->selectionColor == color)
163         return;
164
165     d->selectionColor = color;
166     QPalette p = d->control->palette();
167     p.setColor(QPalette::Highlight, d->selectionColor);
168     d->control->setPalette(p);
169     emit selectionColorChanged(color);
170 }
171
172 /*!
173     \qmlproperty color TextInput::selectedTextColor
174
175     The highlighted text color, used in selections.
176 */
177 QColor QDeclarativeTextInput::selectedTextColor() const
178 {
179     Q_D(const QDeclarativeTextInput);
180     return d->selectedTextColor;
181 }
182
183 void QDeclarativeTextInput::setSelectedTextColor(const QColor &color)
184 {
185     Q_D(QDeclarativeTextInput);
186     if (d->selectedTextColor == color)
187         return;
188
189     d->selectedTextColor = color;
190     QPalette p = d->control->palette();
191     p.setColor(QPalette::HighlightedText, d->selectedTextColor);
192     d->control->setPalette(p);
193     emit selectedTextColorChanged(color);
194 }
195
196 /*!
197     \qmlproperty enumeration TextInput::horizontalAlignment
198
199     Sets the horizontal alignment of the text within the TextInput item's
200     width and height.  By default, the text is left aligned.
201
202     TextInput does not have vertical alignment, as the natural height is
203     exactly the height of the single line of text. If you set the height
204     manually to something larger, TextInput will always be top aligned
205     vertically. You can use anchors to align it however you want within
206     another item.
207
208     The valid values for \c horizontalAlignment are \c AlignLeft, \c AlignRight and
209     \c AlignHCenter.
210 */
211 QDeclarativeTextInput::HAlignment QDeclarativeTextInput::hAlign() const
212 {
213     Q_D(const QDeclarativeTextInput);
214     return d->hAlign;
215 }
216
217 void QDeclarativeTextInput::setHAlign(HAlignment align)
218 {
219     Q_D(QDeclarativeTextInput);
220     if(align == d->hAlign)
221         return;
222     d->hAlign = align;
223     emit horizontalAlignmentChanged(d->hAlign);
224 }
225
226 bool QDeclarativeTextInput::isReadOnly() const
227 {
228     Q_D(const QDeclarativeTextInput);
229     return d->control->isReadOnly();
230 }
231
232 void QDeclarativeTextInput::setReadOnly(bool ro)
233 {
234     Q_D(QDeclarativeTextInput);
235     if (d->control->isReadOnly() == ro)
236         return;
237
238     d->control->setReadOnly(ro);
239
240     emit readOnlyChanged(ro);
241 }
242
243 int QDeclarativeTextInput::maxLength() const
244 {
245     Q_D(const QDeclarativeTextInput);
246     return d->control->maxLength();
247 }
248
249 void QDeclarativeTextInput::setMaxLength(int ml)
250 {
251     Q_D(QDeclarativeTextInput);
252     if (d->control->maxLength() == ml)
253         return;
254
255     d->control->setMaxLength(ml);
256
257     emit maximumLengthChanged(ml);
258 }
259
260 /*!
261     \qmlproperty bool TextInput::cursorVisible
262     Set to true when the TextInput shows a cursor.
263
264     This property is set and unset when the TextInput gets focus, so that other
265     properties can be bound to whether the cursor is currently showing. As it
266     gets set and unset automatically, when you set the value yourself you must
267     keep in mind that your value may be overwritten.
268
269     It can be set directly in script, for example if a KeyProxy might
270     forward keys to it and you desire it to look active when this happens
271     (but without actually giving it the focus).
272
273     It should not be set directly on the element, like in the below QML,
274     as the specified value will be overridden an lost on focus changes.
275
276     \code
277     TextInput {
278         text: "Text"
279         cursorVisible: false
280     }
281     \endcode
282
283     In the above snippet the cursor will still become visible when the
284     TextInput gains focus.
285 */
286 bool QDeclarativeTextInput::isCursorVisible() const
287 {
288     Q_D(const QDeclarativeTextInput);
289     return d->cursorVisible;
290 }
291
292 void QDeclarativeTextInput::setCursorVisible(bool on)
293 {
294     Q_D(QDeclarativeTextInput);
295     if (d->cursorVisible == on)
296         return;
297     d->cursorVisible = on;
298     d->control->setCursorBlinkPeriod(on?QApplication::cursorFlashTime():0);
299     //d->control should emit the cursor update regions
300     emit cursorVisibleChanged(d->cursorVisible);
301 }
302
303 /*!
304     \qmlproperty int TextInput::cursorPosition
305     The position of the cursor in the TextInput.
306 */
307 int QDeclarativeTextInput::cursorPosition() const
308 {
309     Q_D(const QDeclarativeTextInput);
310     return d->control->cursor();
311 }
312 void QDeclarativeTextInput::setCursorPosition(int cp)
313 {
314     Q_D(QDeclarativeTextInput);
315     d->control->moveCursor(cp);
316 }
317
318 /*!
319   \internal
320
321   Returns a Rect which encompasses the cursor, but which may be larger than is
322   required. Ignores custom cursor delegates.
323 */
324 QRect QDeclarativeTextInput::cursorRect() const
325 {
326     Q_D(const QDeclarativeTextInput);
327     return d->control->cursorRect();
328 }
329
330 /*!
331     \qmlproperty int TextInput::selectionStart
332
333     The cursor position before the first character in the current selection.
334     Setting this and selectionEnd allows you to specify a selection in the
335     text edit.
336
337     Note that if selectionStart == selectionEnd then there is no current
338     selection. If you attempt to set selectionStart to a value outside of
339     the current text, selectionStart will not be changed.
340
341     \sa selectionEnd, cursorPosition, selectedText
342 */
343 int QDeclarativeTextInput::selectionStart() const
344 {
345     Q_D(const QDeclarativeTextInput);
346     return d->lastSelectionStart;
347 }
348
349 void QDeclarativeTextInput::setSelectionStart(int s)
350 {
351     Q_D(QDeclarativeTextInput);
352     if(d->lastSelectionStart == s || s < 0 || s > text().length())
353         return;
354     d->lastSelectionStart = s;
355     d->control->setSelection(s, d->lastSelectionEnd - s);
356 }
357
358 /*!
359     \qmlproperty int TextInput::selectionEnd
360
361     The cursor position after the last character in the current selection.
362     Setting this and selectionStart allows you to specify a selection in the
363     text edit.
364
365     Note that if selectionStart == selectionEnd then there is no current
366     selection. If you attempt to set selectionEnd to a value outside of
367     the current text, selectionEnd will not be changed.
368
369     \sa selectionStart, cursorPosition, selectedText
370 */
371 int QDeclarativeTextInput::selectionEnd() const
372 {
373     Q_D(const QDeclarativeTextInput);
374     return d->lastSelectionEnd;
375 }
376
377 void QDeclarativeTextInput::setSelectionEnd(int s)
378 {
379     Q_D(QDeclarativeTextInput);
380     if(d->lastSelectionEnd == s || s < 0 || s > text().length())
381         return;
382     d->lastSelectionEnd = s;
383     d->control->setSelection(d->lastSelectionStart, s - d->lastSelectionStart);
384 }
385
386 /*!
387     \qmlproperty string TextInput::selectedText
388
389     This read-only property provides the text currently selected in the
390     text input.
391
392     It is equivalent to the following snippet, but is faster and easier
393     to use.
394
395     \qml
396     myTextInput.text.toString().substring(myTextInput.selectionStart,
397         myTextInput.selectionEnd);
398     \endqml
399 */
400 QString QDeclarativeTextInput::selectedText() const
401 {
402     Q_D(const QDeclarativeTextInput);
403     return d->control->selectedText();
404 }
405
406 /*!
407     \qmlproperty bool TextInput::focusOnPress
408
409     Whether the TextInput should gain focus on a mouse press. By default this is
410     set to true.
411 */
412 bool QDeclarativeTextInput::focusOnPress() const
413 {
414     Q_D(const QDeclarativeTextInput);
415     return d->focusOnPress;
416 }
417
418 void QDeclarativeTextInput::setFocusOnPress(bool b)
419 {
420     Q_D(QDeclarativeTextInput);
421     if (d->focusOnPress == b)
422         return;
423
424     d->focusOnPress = b;
425
426     emit focusOnPressChanged(d->focusOnPress);
427 }
428
429 /*!
430     \qmlproperty QValidator* TextInput::validator
431
432     Allows you to set a QValidator on the TextInput. When a validator is set
433     the TextInput will only accept input which leaves the text property in
434     an acceptable or intermediate state. The accepted signal will only be sent
435     if the text is in an acceptable state when enter is pressed.
436
437     Currently supported validators are QIntValidator, QDoubleValidator and
438     QRegExpValidator. For details, refer to their C++ documentation and remember
439     that all Q_PROPERTIES are accessible from Qml. A brief usage guide follows:
440
441     QIntValidator and QDoubleValidator both are controllable through two properties,
442     top and bottom. The difference is that for QIntValidator the top and bottom properties
443     should be integers, and for QDoubleValidator they should be doubles. QRegExpValidator
444     has a single string property, regExp, which should be set to the regular expression to
445     be used for validation. An example of using validators is shown below, which allows
446     input of integers between 11 and 31 into the text input:
447
448     \code
449     import Qt 4.6
450     TextInput{
451         validator: QIntValidator{bottom: 11; top: 31;}
452         focus: true
453     }
454     \endcode
455
456     \sa acceptableInput, inputMask
457 */
458 QValidator* QDeclarativeTextInput::validator() const
459 {
460     Q_D(const QDeclarativeTextInput);
461     //###const cast isn't good, but needed for property system?
462     return const_cast<QValidator*>(d->control->validator());
463 }
464
465 void QDeclarativeTextInput::setValidator(QValidator* v)
466 {
467     Q_D(QDeclarativeTextInput);
468     if (d->control->validator() == v)
469         return;
470
471     d->control->setValidator(v);
472     if(!d->control->hasAcceptableInput()){
473         d->oldValidity = false;
474         emit acceptableInputChanged();
475     }
476
477     emit validatorChanged();
478 }
479
480 /*!
481     \qmlproperty string TextInput::inputMask
482
483     Allows you to set an input mask on the TextInput, restricting the allowable
484     text inputs. See QLineEdit::inputMask for further details, as the exact
485     same mask strings are used by TextInput.
486
487     \sa acceptableInput, validator
488 */
489 QString QDeclarativeTextInput::inputMask() const
490 {
491     Q_D(const QDeclarativeTextInput);
492     return d->control->inputMask();
493 }
494
495 void QDeclarativeTextInput::setInputMask(const QString &im)
496 {
497     Q_D(QDeclarativeTextInput);
498     if (d->control->inputMask() == im)
499         return;
500
501     d->control->setInputMask(im);
502     emit inputMaskChanged(d->control->inputMask());
503 }
504
505 /*!
506     \qmlproperty bool TextInput::acceptableInput
507
508     This property is always true unless a validator or input mask has been set.
509     If a validator or input mask has been set, this property will only be true
510     if the current text is acceptable to the validator or input mask as a final
511     string (not as an intermediate string).
512 */
513 bool QDeclarativeTextInput::hasAcceptableInput() const
514 {
515     Q_D(const QDeclarativeTextInput);
516     return d->control->hasAcceptableInput();
517 }
518
519 /*!
520     \qmlproperty TextInput.EchoMode TextInput::echoMode
521
522     Specifies how the text should be displayed in the TextInput.
523     The default is Normal, which displays the text as it is. Other values
524     are Password, which displays asterixes instead of characters, NoEcho,
525     which displays nothing, and PasswordEchoOnEdit, which displays all but the
526     current character as asterixes.
527
528 */
529 QDeclarativeTextInput::EchoMode QDeclarativeTextInput::echoMode() const
530 {
531     Q_D(const QDeclarativeTextInput);
532     return (QDeclarativeTextInput::EchoMode)d->control->echoMode();
533 }
534
535 void QDeclarativeTextInput::setEchoMode(QDeclarativeTextInput::EchoMode echo)
536 {
537     Q_D(QDeclarativeTextInput);
538     if (echoMode() == echo)
539         return;
540
541     d->control->setEchoMode((uint)echo);
542     emit echoModeChanged(echoMode());
543 }
544
545 /*!
546     \qmlproperty Component TextInput::cursorDelegate
547     The delegate for the cursor in the TextInput.
548
549     If you set a cursorDelegate for a TextInput, this delegate will be used for
550     drawing the cursor instead of the standard cursor. An instance of the
551     delegate will be created and managed by the TextInput when a cursor is
552     needed, and the x property of delegate instance will be set so as
553     to be one pixel before the top left of the current character.
554
555     Note that the root item of the delegate component must be a QDeclarativeItem or
556     QDeclarativeItem derived item.
557 */
558 QDeclarativeComponent* QDeclarativeTextInput::cursorDelegate() const
559 {
560     Q_D(const QDeclarativeTextInput);
561     return d->cursorComponent;
562 }
563
564 void QDeclarativeTextInput::setCursorDelegate(QDeclarativeComponent* c)
565 {
566     Q_D(QDeclarativeTextInput);
567     if (d->cursorComponent == c)
568         return;
569
570     d->cursorComponent = c;
571     if(!c){
572         //note that the components are owned by something else
573         disconnect(d->control, SIGNAL(cursorPositionChanged(int, int)),
574                 this, SLOT(moveCursor()));
575         delete d->cursorItem;
576     }else{
577         d->startCreatingCursor();
578     }
579
580     emit cursorDelegateChanged();
581 }
582
583 void QDeclarativeTextInputPrivate::startCreatingCursor()
584 {
585     Q_Q(QDeclarativeTextInput);
586     q->connect(control, SIGNAL(cursorPositionChanged(int, int)),
587             q, SLOT(moveCursor()));
588     if(cursorComponent->isReady()){
589         q->createCursor();
590     }else if(cursorComponent->isLoading()){
591         q->connect(cursorComponent, SIGNAL(statusChanged(int)),
592                 q, SLOT(createCursor()));
593     }else{//isError
594         qmlInfo(q) << QDeclarativeTextInput::tr("Could not load cursor delegate");
595         qWarning() << cursorComponent->errors();
596     }
597 }
598
599 void QDeclarativeTextInput::createCursor()
600 {
601     Q_D(QDeclarativeTextInput);
602     if(d->cursorComponent->isError()){
603         qmlInfo(this) << tr("Could not load cursor delegate");
604         qWarning() << d->cursorComponent->errors();
605         return;
606     }
607
608     if(!d->cursorComponent->isReady())
609         return;
610
611     if(d->cursorItem)
612         delete d->cursorItem;
613     d->cursorItem = qobject_cast<QDeclarativeItem*>(d->cursorComponent->create());
614     if(!d->cursorItem){
615         qmlInfo(this) << tr("Could not instantiate cursor delegate");
616         //The failed instantiation should print its own error messages
617         return;
618     }
619
620     d->cursorItem->setParentItem(this);
621     d->cursorItem->setX(d->control->cursorToX());
622     d->cursorItem->setHeight(d->control->height());
623 }
624
625 void QDeclarativeTextInput::moveCursor()
626 {
627     Q_D(QDeclarativeTextInput);
628     if(!d->cursorItem)
629         return;
630     d->cursorItem->setX(d->control->cursorToX() - d->hscroll);
631 }
632
633 int QDeclarativeTextInput::xToPos(int x)
634 {
635     Q_D(const QDeclarativeTextInput);
636     return d->control->xToPos(x - d->hscroll);
637 }
638
639 void QDeclarativeTextInput::focusChanged(bool hasFocus)
640 {
641     Q_D(QDeclarativeTextInput);
642     d->focused = hasFocus;
643     setCursorVisible(hasFocus);
644     QDeclarativeItem::focusChanged(hasFocus);
645 }
646
647 void QDeclarativeTextInput::keyPressEvent(QKeyEvent* ev)
648 {
649     Q_D(QDeclarativeTextInput);
650     if(((d->control->cursor() == 0 && ev->key() == Qt::Key_Left)
651             || (d->control->cursor() == d->control->text().length()
652                 && ev->key() == Qt::Key_Right))
653             && (d->lastSelectionStart == d->lastSelectionEnd)){
654         //ignore when moving off the end
655         //unless there is a selection, because then moving will do something (deselect)
656         ev->ignore();
657     }else{
658         d->control->processKeyEvent(ev);
659     }
660     if (!ev->isAccepted())
661         QDeclarativePaintedItem::keyPressEvent(ev);
662 }
663
664 void QDeclarativeTextInput::mousePressEvent(QGraphicsSceneMouseEvent *event)
665 {
666     Q_D(QDeclarativeTextInput);
667     if(d->focusOnPress){
668         QGraphicsItem *p = parentItem();//###Is there a better way to find my focus scope?
669         while(p) {
670             if(p->flags() & QGraphicsItem::ItemIsFocusScope){
671                 p->setFocus();
672                 break;
673             }
674             p = p->parentItem();
675         }
676         setFocus(true);
677     }
678     d->control->processEvent(event);
679 }
680
681 /*!
682 \overload
683 Handles the given mouse \a event.
684 */
685 void QDeclarativeTextInput::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
686 {
687     Q_D(QDeclarativeTextInput);
688     QWidget *widget = event->widget();
689     if (widget && !d->control->isReadOnly() && boundingRect().contains(event->pos()))
690         qt_widget_private(widget)->handleSoftwareInputPanel(event->button(), d->focusOnPress);
691     d->control->processEvent(event);
692 }
693
694 bool QDeclarativeTextInput::event(QEvent* ev)
695 {
696     Q_D(QDeclarativeTextInput);
697     //Anything we don't deal with ourselves, pass to the control
698     bool handled = false;
699     switch(ev->type()){
700         case QEvent::KeyPress:
701         case QEvent::KeyRelease://###Should the control be doing anything with release?
702         case QEvent::GraphicsSceneMousePress:
703         case QEvent::GraphicsSceneMouseRelease:
704             break;
705         default:
706             handled = d->control->processEvent(ev);
707             if (ev->type() == QEvent::InputMethod)
708                 updateSize();
709     }
710     if(!handled)
711         return QDeclarativePaintedItem::event(ev);
712     return true;
713 }
714
715 void QDeclarativeTextInput::geometryChanged(const QRectF &newGeometry,
716                                   const QRectF &oldGeometry)
717 {
718     if (newGeometry.width() != oldGeometry.width())
719         updateSize();
720     QDeclarativePaintedItem::geometryChanged(newGeometry, oldGeometry);
721 }
722
723 void QDeclarativeTextInput::drawContents(QPainter *p, const QRect &r)
724 {
725     Q_D(QDeclarativeTextInput);
726     p->setRenderHint(QPainter::TextAntialiasing, true);
727     p->save();
728     p->setPen(QPen(d->color));
729     int flags = QLineControl::DrawText;
730     if(!isReadOnly() && d->cursorVisible && !d->cursorItem)
731         flags |= QLineControl::DrawCursor;
732     if (d->control->hasSelectedText()){
733             flags |= QLineControl::DrawSelections;
734     }
735
736     QPoint offset = QPoint(0,0);
737     if(d->hAlign != AlignLeft){
738         QFontMetrics fm = QFontMetrics(d->font);
739         //###Is this using bearing appropriately?
740         int minLB = qMax(0, -fm.minLeftBearing());
741         int minRB = qMax(0, -fm.minRightBearing());
742         int widthUsed = qRound(d->control->naturalTextWidth()) + 1 + minRB;
743         int hOffset = 0;
744         if(d->hAlign == AlignRight){
745             hOffset = width() - widthUsed;
746         }else if(d->hAlign == AlignHCenter){
747             hOffset = (width() - widthUsed) / 2;
748         }
749         hOffset -= minLB;
750         offset = QPoint(hOffset, 0);
751     }
752     QRect clipRect = r;
753     d->control->draw(p, offset, clipRect, flags);
754
755     p->restore();
756 }
757
758 /*!
759 \overload
760 Returns the value of the given \a property.
761 */
762 QVariant QDeclarativeTextInput::inputMethodQuery(Qt::InputMethodQuery property) const
763 {
764     Q_D(const QDeclarativeTextInput);
765     switch(property) {
766     case Qt::ImFont:
767         return font();
768     case Qt::ImCursorPosition:
769         return QVariant(d->control->cursor());
770     case Qt::ImSurroundingText:
771         return QVariant(text());
772     case Qt::ImCurrentSelection:
773         return QVariant(selectedText());
774     case Qt::ImMaximumTextLength:
775         return QVariant(maxLength());
776     case Qt::ImAnchorPosition:
777         if (d->control->selectionStart() == d->control->selectionEnd())
778             return QVariant(d->control->cursor());
779         else if (d->control->selectionStart() == d->control->cursor())
780             return QVariant(d->control->selectionEnd());
781         else
782             return QVariant(d->control->selectionStart());
783     default:
784         return QVariant();
785     }
786 }
787
788 void QDeclarativeTextInput::selectAll()
789 {
790     Q_D(QDeclarativeTextInput);
791     d->control->setSelection(0, d->control->text().length());
792 }
793
794
795 /*!
796     \qmlproperty bool TextInput::smooth
797
798     Set this property if you want the text to be smoothly scaled or
799     transformed.  Smooth filtering gives better visual quality, but is slower.  If
800     the item is displayed at its natural size, this property has no visual or
801     performance effect.
802
803     \note Generally scaling artifacts are only visible if the item is stationary on
804     the screen.  A common pattern when animating an item is to disable smooth
805     filtering at the beginning of the animation and reenable it at the conclusion.
806 */
807
808 void QDeclarativeTextInputPrivate::init()
809 {
810     Q_Q(QDeclarativeTextInput);
811     control->setCursorWidth(1);
812     control->setPasswordCharacter(QLatin1Char('*'));
813     control->setLayoutDirection(Qt::LeftToRight);
814     q->setSmooth(smooth);
815     q->setAcceptedMouseButtons(Qt::LeftButton);
816     q->setFlag(QGraphicsItem::ItemHasNoContents, false);
817     q->setFlag(QGraphicsItem::ItemAcceptsInputMethod);
818     q->connect(control, SIGNAL(cursorPositionChanged(int,int)),
819                q, SLOT(cursorPosChanged()));
820     q->connect(control, SIGNAL(selectionChanged()),
821                q, SLOT(selectionChanged()));
822     q->connect(control, SIGNAL(textChanged(const QString &)),
823                q, SLOT(q_textChanged()));
824     q->connect(control, SIGNAL(accepted()),
825                q, SIGNAL(accepted()));
826     q->connect(control, SIGNAL(updateNeeded(QRect)),
827                q, SLOT(updateRect(QRect)));
828     q->connect(control, SIGNAL(cursorPositionChanged(int,int)),
829                q, SLOT(updateRect()));//TODO: Only update rect between pos's
830     q->connect(control, SIGNAL(selectionChanged()),
831                q, SLOT(updateRect()));//TODO: Only update rect in selection
832     //Note that above TODOs probably aren't that big a savings
833     q->updateSize();
834     oldValidity = control->hasAcceptableInput();
835     lastSelectionStart = 0;
836     lastSelectionEnd = 0;
837 }
838
839 void QDeclarativeTextInput::cursorPosChanged()
840 {
841     Q_D(QDeclarativeTextInput);
842     emit cursorPositionChanged();
843
844     if(!d->control->hasSelectedText()){
845         if(d->lastSelectionStart != d->control->cursor()){
846             d->lastSelectionStart = d->control->cursor();
847             emit selectionStartChanged();
848         }
849         if(d->lastSelectionEnd != d->control->cursor()){
850             d->lastSelectionEnd = d->control->cursor();
851             emit selectionEndChanged();
852         }
853     }
854 }
855
856 void QDeclarativeTextInput::selectionChanged()
857 {
858     Q_D(QDeclarativeTextInput);
859     emit selectedTextChanged();
860
861     if(d->lastSelectionStart != d->control->selectionStart()){
862         d->lastSelectionStart = d->control->selectionStart();
863         if(d->lastSelectionStart == -1)
864             d->lastSelectionStart = d->control->cursor();
865         emit selectionStartChanged();
866     }
867     if(d->lastSelectionEnd != d->control->selectionEnd()){
868         d->lastSelectionEnd = d->control->selectionEnd();
869         if(d->lastSelectionEnd == -1)
870             d->lastSelectionEnd = d->control->cursor();
871         emit selectionEndChanged();
872     }
873 }
874
875 void QDeclarativeTextInput::q_textChanged()
876 {
877     Q_D(QDeclarativeTextInput);
878     updateSize();
879     emit textChanged();
880     if(hasAcceptableInput() != d->oldValidity){
881         d->oldValidity = hasAcceptableInput();
882         emit acceptableInputChanged();
883     }
884 }
885
886 void QDeclarativeTextInput::updateRect(const QRect &r)
887 {
888     if(r == QRect())
889         clearCache();
890     else
891         dirtyCache(r);
892     update();
893 }
894
895 void QDeclarativeTextInput::updateSize(bool needsRedraw)
896 {
897     Q_D(QDeclarativeTextInput);
898     int w = width();
899     int h = height();
900     setImplicitHeight(d->control->height());
901     int cursorWidth = d->control->cursorWidth();
902     if(d->cursorItem)
903         cursorWidth = d->cursorItem->width();
904     //### Is QFontMetrics too slow?
905     QFontMetricsF fm(d->font);
906     setImplicitWidth(fm.width(d->control->displayText())+cursorWidth);
907     setContentsSize(QSize(width(), height()));//Repaints if changed
908     if(w==width() && h==height() && needsRedraw){
909         clearCache();
910         update();
911     }
912 }
913
914 QT_END_NAMESPACE
915