src/declarative/graphicsitems/qdeclarativetextinput.cpp
changeset 30 5dc02b23752f
child 33 3e2da88830cd
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/declarative/graphicsitems/qdeclarativetextinput.cpp	Tue Jul 06 15:10:48 2010 +0300
@@ -0,0 +1,1288 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights.  These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "private/qdeclarativetextinput_p.h"
+#include "private/qdeclarativetextinput_p_p.h"
+
+#include <private/qdeclarativeglobal_p.h>
+#include <qdeclarativeinfo.h>
+
+#include <QValidator>
+#include <QApplication>
+#include <QFontMetrics>
+#include <QPainter>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+    \qmlclass TextInput QDeclarativeTextInput
+  \since 4.7
+    \brief The TextInput item allows you to add an editable line of text to a scene.
+
+    TextInput can only display a single line of text, and can only display
+    plain text. However it can provide addition input constraints on the text.
+
+    Input constraints include setting a QValidator, an input mask, or a
+    maximum input length.
+
+    On Mac OS X, the Up/Down key bindings for Home/End are explicitly disabled.
+    If you want such bindings (on any platform), you will need to construct them in QML.
+*/
+QDeclarativeTextInput::QDeclarativeTextInput(QDeclarativeItem* parent)
+    : QDeclarativePaintedItem(*(new QDeclarativeTextInputPrivate), parent)
+{
+    Q_D(QDeclarativeTextInput);
+    d->init();
+}
+
+QDeclarativeTextInput::~QDeclarativeTextInput()
+{
+}
+
+/*!
+    \qmlproperty string TextInput::text
+
+    The text in the TextInput.
+*/
+
+QString QDeclarativeTextInput::text() const
+{
+    Q_D(const QDeclarativeTextInput);
+    return d->control->text();
+}
+
+void QDeclarativeTextInput::setText(const QString &s)
+{
+    Q_D(QDeclarativeTextInput);
+    if(s == text())
+        return;
+    d->control->setText(s);
+    //emit textChanged();
+}
+
+/*!
+    \qmlproperty string TextInput::font.family
+
+    Sets the family name of the font.
+
+    The family name is case insensitive and may optionally include a foundry name, e.g. "Helvetica [Cronyx]".
+    If the family is available from more than one foundry and the foundry isn't specified, an arbitrary foundry is chosen.
+    If the family isn't available a family will be set using the font matching algorithm.
+*/
+
+/*!
+    \qmlproperty bool TextInput::font.bold
+
+    Sets whether the font weight is bold.
+*/
+
+/*!
+    \qmlproperty enumeration TextInput::font.weight
+
+    Sets the font's weight.
+
+    The weight can be one of:
+    \list
+    \o Font.Light
+    \o Font.Normal - the default
+    \o Font.DemiBold
+    \o Font.Bold
+    \o Font.Black
+    \endlist
+
+    \qml
+    TextInput { text: "Hello"; font.weight: Font.DemiBold }
+    \endqml
+*/
+
+/*!
+    \qmlproperty bool TextInput::font.italic
+
+    Sets whether the font has an italic style.
+*/
+
+/*!
+    \qmlproperty bool TextInput::font.underline
+
+    Sets whether the text is underlined.
+*/
+
+/*!
+    \qmlproperty bool TextInput::font.outline
+
+    Sets whether the font has an outline style.
+*/
+
+/*!
+    \qmlproperty bool TextInput::font.strikeout
+
+    Sets whether the font has a strikeout style.
+*/
+
+/*!
+    \qmlproperty real TextInput::font.pointSize
+
+    Sets the font size in points. The point size must be greater than zero.
+*/
+
+/*!
+    \qmlproperty int TextInput::font.pixelSize
+
+    Sets the font size in pixels.
+
+    Using this function makes the font device dependent.
+    Use \c pointSize to set the size of the font in a device independent manner.
+*/
+
+/*!
+    \qmlproperty real TextInput::font.letterSpacing
+
+    Sets the letter spacing for the font.
+
+    Letter spacing changes the default spacing between individual letters in the font.
+    A value of 100 will keep the spacing unchanged; a value of 200 will enlarge the spacing after a character by
+    the width of the character itself.
+*/
+
+/*!
+    \qmlproperty real TextInput::font.wordSpacing
+
+    Sets the word spacing for the font.
+
+    Word spacing changes the default spacing between individual words.
+    A positive value increases the word spacing by a corresponding amount of pixels,
+    while a negative value decreases the inter-word spacing accordingly.
+*/
+
+/*!
+    \qmlproperty enumeration TextInput::font.capitalization
+
+    Sets the capitalization for the text.
+
+    \list
+    \o Font.MixedCase - This is the normal text rendering option where no capitalization change is applied.
+    \o Font.AllUppercase - This alters the text to be rendered in all uppercase type.
+    \o Font.AllLowercase	 - This alters the text to be rendered in all lowercase type.
+    \o Font.SmallCaps -	This alters the text to be rendered in small-caps type.
+    \o Font.Capitalize - This alters the text to be rendered with the first character of each word as an uppercase character.
+    \endlist
+
+    \qml
+    TextInput { text: "Hello"; font.capitalization: Font.AllLowercase }
+    \endqml
+*/
+
+QFont QDeclarativeTextInput::font() const
+{
+    Q_D(const QDeclarativeTextInput);
+    return d->font;
+}
+
+void QDeclarativeTextInput::setFont(const QFont &font)
+{
+    Q_D(QDeclarativeTextInput);
+    if (d->font == font)
+        return;
+
+    d->font = font;
+
+    d->control->setFont(d->font);
+    if(d->cursorItem){
+        d->cursorItem->setHeight(QFontMetrics(d->font).height());
+        moveCursor();
+    }
+    updateSize();
+    emit fontChanged(d->font);
+}
+
+/*!
+    \qmlproperty color TextInput::color
+
+    The text color.
+*/
+QColor QDeclarativeTextInput::color() const
+{
+    Q_D(const QDeclarativeTextInput);
+    return d->color;
+}
+
+void QDeclarativeTextInput::setColor(const QColor &c)
+{
+    Q_D(QDeclarativeTextInput);
+    d->color = c;
+}
+
+
+/*!
+    \qmlproperty color TextInput::selectionColor
+
+    The text highlight color, used behind selections.
+*/
+QColor QDeclarativeTextInput::selectionColor() const
+{
+    Q_D(const QDeclarativeTextInput);
+    return d->selectionColor;
+}
+
+void QDeclarativeTextInput::setSelectionColor(const QColor &color)
+{
+    Q_D(QDeclarativeTextInput);
+    if (d->selectionColor == color)
+        return;
+
+    d->selectionColor = color;
+    QPalette p = d->control->palette();
+    p.setColor(QPalette::Highlight, d->selectionColor);
+    d->control->setPalette(p);
+    emit selectionColorChanged(color);
+}
+
+/*!
+    \qmlproperty color TextInput::selectedTextColor
+
+    The highlighted text color, used in selections.
+*/
+QColor QDeclarativeTextInput::selectedTextColor() const
+{
+    Q_D(const QDeclarativeTextInput);
+    return d->selectedTextColor;
+}
+
+void QDeclarativeTextInput::setSelectedTextColor(const QColor &color)
+{
+    Q_D(QDeclarativeTextInput);
+    if (d->selectedTextColor == color)
+        return;
+
+    d->selectedTextColor = color;
+    QPalette p = d->control->palette();
+    p.setColor(QPalette::HighlightedText, d->selectedTextColor);
+    d->control->setPalette(p);
+    emit selectedTextColorChanged(color);
+}
+
+/*!
+    \qmlproperty enumeration TextInput::horizontalAlignment
+
+    Sets the horizontal alignment of the text within the TextInput item's
+    width and height.  By default, the text is left aligned.
+
+    TextInput does not have vertical alignment, as the natural height is
+    exactly the height of the single line of text. If you set the height
+    manually to something larger, TextInput will always be top aligned
+    vertically. You can use anchors to align it however you want within
+    another item.
+
+    The valid values for \c horizontalAlignment are \c TextInput.AlignLeft, \c TextInput.AlignRight and
+    \c TextInput.AlignHCenter.
+*/
+QDeclarativeTextInput::HAlignment QDeclarativeTextInput::hAlign() const
+{
+    Q_D(const QDeclarativeTextInput);
+    return d->hAlign;
+}
+
+void QDeclarativeTextInput::setHAlign(HAlignment align)
+{
+    Q_D(QDeclarativeTextInput);
+    if(align == d->hAlign)
+        return;
+    d->hAlign = align;
+    updateRect();
+    emit horizontalAlignmentChanged(d->hAlign);
+}
+
+bool QDeclarativeTextInput::isReadOnly() const
+{
+    Q_D(const QDeclarativeTextInput);
+    return d->control->isReadOnly();
+}
+
+void QDeclarativeTextInput::setReadOnly(bool ro)
+{
+    Q_D(QDeclarativeTextInput);
+    if (d->control->isReadOnly() == ro)
+        return;
+
+    d->control->setReadOnly(ro);
+
+    emit readOnlyChanged(ro);
+}
+
+int QDeclarativeTextInput::maxLength() const
+{
+    Q_D(const QDeclarativeTextInput);
+    return d->control->maxLength();
+}
+
+void QDeclarativeTextInput::setMaxLength(int ml)
+{
+    Q_D(QDeclarativeTextInput);
+    if (d->control->maxLength() == ml)
+        return;
+
+    d->control->setMaxLength(ml);
+
+    emit maximumLengthChanged(ml);
+}
+
+/*!
+    \qmlproperty bool TextInput::cursorVisible
+    Set to true when the TextInput shows a cursor.
+
+    This property is set and unset when the TextInput gets focus, so that other
+    properties can be bound to whether the cursor is currently showing. As it
+    gets set and unset automatically, when you set the value yourself you must
+    keep in mind that your value may be overwritten.
+
+    It can be set directly in script, for example if a KeyProxy might
+    forward keys to it and you desire it to look active when this happens
+    (but without actually giving it the focus).
+
+    It should not be set directly on the element, like in the below QML,
+    as the specified value will be overridden an lost on focus changes.
+
+    \code
+    TextInput {
+        text: "Text"
+        cursorVisible: false
+    }
+    \endcode
+
+    In the above snippet the cursor will still become visible when the
+    TextInput gains focus.
+*/
+bool QDeclarativeTextInput::isCursorVisible() const
+{
+    Q_D(const QDeclarativeTextInput);
+    return d->cursorVisible;
+}
+
+void QDeclarativeTextInput::setCursorVisible(bool on)
+{
+    Q_D(QDeclarativeTextInput);
+    if (d->cursorVisible == on)
+        return;
+    d->cursorVisible = on;
+    d->control->setCursorBlinkPeriod(on?QApplication::cursorFlashTime():0);
+    //d->control should emit the cursor update regions
+    emit cursorVisibleChanged(d->cursorVisible);
+}
+
+/*!
+    \qmlproperty int TextInput::cursorPosition
+    The position of the cursor in the TextInput.
+*/
+int QDeclarativeTextInput::cursorPosition() const
+{
+    Q_D(const QDeclarativeTextInput);
+    return d->control->cursor();
+}
+void QDeclarativeTextInput::setCursorPosition(int cp)
+{
+    Q_D(QDeclarativeTextInput);
+    d->control->moveCursor(cp);
+}
+
+/*!
+  \internal
+
+  Returns a Rect which encompasses the cursor, but which may be larger than is
+  required. Ignores custom cursor delegates.
+*/
+QRect QDeclarativeTextInput::cursorRect() const
+{
+    Q_D(const QDeclarativeTextInput);
+    return d->control->cursorRect();
+}
+
+/*!
+    \qmlproperty int TextInput::selectionStart
+
+    The cursor position before the first character in the current selection.
+    Setting this and selectionEnd allows you to specify a selection in the
+    text edit.
+
+    Note that if selectionStart == selectionEnd then there is no current
+    selection. If you attempt to set selectionStart to a value outside of
+    the current text, selectionStart will not be changed.
+
+    \sa selectionEnd, cursorPosition, selectedText
+*/
+int QDeclarativeTextInput::selectionStart() const
+{
+    Q_D(const QDeclarativeTextInput);
+    return d->lastSelectionStart;
+}
+
+void QDeclarativeTextInput::setSelectionStart(int s)
+{
+    Q_D(QDeclarativeTextInput);
+    if(d->lastSelectionStart == s || s < 0 || s > text().length())
+        return;
+    d->lastSelectionStart = s;
+    d->control->setSelection(s, d->lastSelectionEnd - s);
+}
+
+/*!
+    \qmlproperty int TextInput::selectionEnd
+
+    The cursor position after the last character in the current selection.
+    Setting this and selectionStart allows you to specify a selection in the
+    text edit.
+
+    Note that if selectionStart == selectionEnd then there is no current
+    selection. If you attempt to set selectionEnd to a value outside of
+    the current text, selectionEnd will not be changed.
+
+    \sa selectionStart, cursorPosition, selectedText
+*/
+int QDeclarativeTextInput::selectionEnd() const
+{
+    Q_D(const QDeclarativeTextInput);
+    return d->lastSelectionEnd;
+}
+
+void QDeclarativeTextInput::setSelectionEnd(int s)
+{
+    Q_D(QDeclarativeTextInput);
+    if(d->lastSelectionEnd == s || s < 0 || s > text().length())
+        return;
+    d->lastSelectionEnd = s;
+    d->control->setSelection(d->lastSelectionStart, s - d->lastSelectionStart);
+}
+
+/*!
+    \qmlproperty string TextInput::selectedText
+
+    This read-only property provides the text currently selected in the
+    text input.
+
+    It is equivalent to the following snippet, but is faster and easier
+    to use.
+
+    \qml
+    myTextInput.text.toString().substring(myTextInput.selectionStart,
+        myTextInput.selectionEnd);
+    \endqml
+*/
+QString QDeclarativeTextInput::selectedText() const
+{
+    Q_D(const QDeclarativeTextInput);
+    return d->control->selectedText();
+}
+
+/*!
+    \qmlproperty bool TextInput::focusOnPress
+
+    Whether the TextInput should gain focus on a mouse press. By default this is
+    set to true.
+*/
+bool QDeclarativeTextInput::focusOnPress() const
+{
+    Q_D(const QDeclarativeTextInput);
+    return d->focusOnPress;
+}
+
+void QDeclarativeTextInput::setFocusOnPress(bool b)
+{
+    Q_D(QDeclarativeTextInput);
+    if (d->focusOnPress == b)
+        return;
+
+    d->focusOnPress = b;
+
+    emit focusOnPressChanged(d->focusOnPress);
+}
+
+/*!
+    \qmlproperty bool TextInput::autoScroll
+
+    Whether the TextInput should scroll when the text is longer than the width. By default this is
+    set to true.
+*/
+bool QDeclarativeTextInput::autoScroll() const
+{
+    Q_D(const QDeclarativeTextInput);
+    return d->autoScroll;
+}
+
+void QDeclarativeTextInput::setAutoScroll(bool b)
+{
+    Q_D(QDeclarativeTextInput);
+    if (d->autoScroll == b)
+        return;
+
+    d->autoScroll = b;
+
+    emit autoScrollChanged(d->autoScroll);
+}
+
+/*!
+    \qmlclass IntValidator QIntValidator
+
+    This element provides a validator for integer values
+*/
+/*!
+    \qmlproperty int IntValidator::top
+
+    This property holds the validator's highest acceptable value.
+    By default, this property's value is derived from the highest signed integer available (typically 2147483647).
+*/
+/*!
+    \qmlproperty int IntValidator::bottom
+
+    This property holds the validator's lowest acceptable value.
+    By default, this property's value is derived from the lowest signed integer available (typically -2147483647).
+*/
+
+/*!
+    \qmlclass DoubleValidator QDoubleValidator
+
+    This element provides a validator for non-integer numbers.
+*/
+
+/*!
+    \qmlproperty real DoubleValidator::top
+
+    This property holds the validator's maximum acceptable value.
+    By default, this property contains a value of infinity.
+*/
+/*!
+    \qmlproperty real DoubleValidator::bottom
+
+    This property holds the validator's minimum acceptable value.
+    By default, this property contains a value of -infinity.
+*/
+/*!
+    \qmlproperty int DoubleValidator::decimals
+
+    This property holds the validator's maximum number of digits after the decimal point.
+    By default, this property contains a value of 1000.
+*/
+/*!
+    \qmlproperty enumeration DoubleValidator::notation
+    This property holds the notation of how a string can describe a number.
+
+    The values for this property are DoubleValidator.StandardNotation or DoubleValidator.ScientificNotation.
+    If this property is set to DoubleValidator.ScientificNotation, the written number may have an exponent part(i.e. 1.5E-2).
+
+    By default, this property is set to DoubleValidator.ScientificNotation.
+*/
+
+/*!
+    \qmlclass RegExpValidator QRegExpValidator
+
+    This element provides a validator, which counts as valid any string which
+    matches a specified regular expression.
+*/
+/*!
+   \qmlproperty regExp RegExpValidator::regExp
+
+   This property holds the regular expression used for validation.
+
+   Note that this property should be a regular expression in JS syntax, e.g /a/ for the regular expression
+   matching "a".
+
+   By default, this property contains a regular expression with the pattern .* that matches any string.
+*/
+
+/*!
+    \qmlproperty Validator TextInput::validator
+
+    Allows you to set a validator on the TextInput. When a validator is set
+    the TextInput will only accept input which leaves the text property in
+    an acceptable or intermediate state. The accepted signal will only be sent
+    if the text is in an acceptable state when enter is pressed.
+
+    Currently supported validators are IntValidator, DoubleValidator and
+    RegExpValidator. An example of using validators is shown below, which allows
+    input of integers between 11 and 31 into the text input:
+
+    \code
+    import Qt 4.7
+    TextInput{
+        validator: IntValidator{bottom: 11; top: 31;}
+        focus: true
+    }
+    \endcode
+
+    \sa acceptableInput, inputMask
+*/
+QValidator* QDeclarativeTextInput::validator() const
+{
+    Q_D(const QDeclarativeTextInput);
+    //###const cast isn't good, but needed for property system?
+    return const_cast<QValidator*>(d->control->validator());
+}
+
+void QDeclarativeTextInput::setValidator(QValidator* v)
+{
+    Q_D(QDeclarativeTextInput);
+    if (d->control->validator() == v)
+        return;
+
+    d->control->setValidator(v);
+    if(!d->control->hasAcceptableInput()){
+        d->oldValidity = false;
+        emit acceptableInputChanged();
+    }
+
+    emit validatorChanged();
+}
+
+/*!
+    \qmlproperty string TextInput::inputMask
+
+    Allows you to set an input mask on the TextInput, restricting the allowable
+    text inputs. See QLineEdit::inputMask for further details, as the exact
+    same mask strings are used by TextInput.
+
+    \sa acceptableInput, validator
+*/
+QString QDeclarativeTextInput::inputMask() const
+{
+    Q_D(const QDeclarativeTextInput);
+    return d->control->inputMask();
+}
+
+void QDeclarativeTextInput::setInputMask(const QString &im)
+{
+    Q_D(QDeclarativeTextInput);
+    if (d->control->inputMask() == im)
+        return;
+
+    d->control->setInputMask(im);
+    emit inputMaskChanged(d->control->inputMask());
+}
+
+/*!
+    \qmlproperty bool TextInput::acceptableInput
+
+    This property is always true unless a validator or input mask has been set.
+    If a validator or input mask has been set, this property will only be true
+    if the current text is acceptable to the validator or input mask as a final
+    string (not as an intermediate string).
+*/
+bool QDeclarativeTextInput::hasAcceptableInput() const
+{
+    Q_D(const QDeclarativeTextInput);
+    return d->control->hasAcceptableInput();
+}
+
+/*!
+    \qmlproperty enumeration TextInput::echoMode
+
+    Specifies how the text should be displayed in the TextInput.
+    \list
+    \o TextInput.Normal - Displays the text as it is. (Default)
+    \o TextInput.Password - Displays asterixes instead of characters.
+    \o TextInput.NoEcho - Displays nothing.
+    \o TextInput.PasswordEchoOnEdit - Displays all but the current character as asterixes.
+    \endlist
+*/
+QDeclarativeTextInput::EchoMode QDeclarativeTextInput::echoMode() const
+{
+    Q_D(const QDeclarativeTextInput);
+    return (QDeclarativeTextInput::EchoMode)d->control->echoMode();
+}
+
+void QDeclarativeTextInput::setEchoMode(QDeclarativeTextInput::EchoMode echo)
+{
+    Q_D(QDeclarativeTextInput);
+    if (echoMode() == echo)
+        return;
+    Qt::InputMethodHints imHints = inputMethodHints();
+    if (echo == Password || echo == NoEcho)
+        imHints |= Qt::ImhHiddenText;
+    else
+        imHints &= ~Qt::ImhHiddenText;
+    if (echo != Normal)
+        imHints |= (Qt::ImhNoAutoUppercase | Qt::ImhNoPredictiveText);
+    else
+        imHints &= ~(Qt::ImhNoAutoUppercase | Qt::ImhNoPredictiveText);
+    setInputMethodHints(imHints);
+    d->control->setEchoMode((uint)echo);
+    update();
+    emit echoModeChanged(echoMode());
+}
+
+/*!
+    \qmlproperty Component TextInput::cursorDelegate
+    The delegate for the cursor in the TextInput.
+
+    If you set a cursorDelegate for a TextInput, this delegate will be used for
+    drawing the cursor instead of the standard cursor. An instance of the
+    delegate will be created and managed by the TextInput when a cursor is
+    needed, and the x property of delegate instance will be set so as
+    to be one pixel before the top left of the current character.
+
+    Note that the root item of the delegate component must be a QDeclarativeItem or
+    QDeclarativeItem derived item.
+*/
+QDeclarativeComponent* QDeclarativeTextInput::cursorDelegate() const
+{
+    Q_D(const QDeclarativeTextInput);
+    return d->cursorComponent;
+}
+
+void QDeclarativeTextInput::setCursorDelegate(QDeclarativeComponent* c)
+{
+    Q_D(QDeclarativeTextInput);
+    if (d->cursorComponent == c)
+        return;
+
+    d->cursorComponent = c;
+    if(!c){
+        //note that the components are owned by something else
+        disconnect(d->control, SIGNAL(cursorPositionChanged(int, int)),
+                this, SLOT(moveCursor()));
+        delete d->cursorItem;
+    }else{
+        d->startCreatingCursor();
+    }
+
+    emit cursorDelegateChanged();
+}
+
+void QDeclarativeTextInputPrivate::startCreatingCursor()
+{
+    Q_Q(QDeclarativeTextInput);
+    q->connect(control, SIGNAL(cursorPositionChanged(int, int)),
+            q, SLOT(moveCursor()));
+    if(cursorComponent->isReady()){
+        q->createCursor();
+    }else if(cursorComponent->isLoading()){
+        q->connect(cursorComponent, SIGNAL(statusChanged(int)),
+                q, SLOT(createCursor()));
+    }else {//isError
+        qmlInfo(q, cursorComponent->errors()) << QDeclarativeTextInput::tr("Could not load cursor delegate");
+    }
+}
+
+void QDeclarativeTextInput::createCursor()
+{
+    Q_D(QDeclarativeTextInput);
+    if(d->cursorComponent->isError()){
+        qmlInfo(this, d->cursorComponent->errors()) << tr("Could not load cursor delegate");
+        return;
+    }
+
+    if(!d->cursorComponent->isReady())
+        return;
+
+    if(d->cursorItem)
+        delete d->cursorItem;
+    d->cursorItem = qobject_cast<QDeclarativeItem*>(d->cursorComponent->create());
+    if(!d->cursorItem){
+        qmlInfo(this, d->cursorComponent->errors()) << tr("Could not instantiate cursor delegate");
+        return;
+    }
+
+    QDeclarative_setParent_noEvent(d->cursorItem, this);
+    d->cursorItem->setParentItem(this);
+    d->cursorItem->setX(d->control->cursorToX());
+    d->cursorItem->setHeight(d->control->height());
+}
+
+void QDeclarativeTextInput::moveCursor()
+{
+    Q_D(QDeclarativeTextInput);
+    if(!d->cursorItem)
+        return;
+    d->cursorItem->setX(d->control->cursorToX() - d->hscroll);
+}
+
+/*!
+    \qmlmethod int TextInput::xToPosition(int x)
+
+    This function returns the character position at
+    x pixels from the left of the textInput. Position 0 is before the
+    first character, position 1 is after the first character but before the second,
+    and so on until position text.length, which is after all characters.
+
+    This means that for all x values before the first character this function returns 0,
+    and for all x values after the last character this function returns text.length.
+*/
+int QDeclarativeTextInput::xToPosition(int x)
+{
+    Q_D(const QDeclarativeTextInput);
+    return d->control->xToPos(x - d->hscroll);
+}
+
+void QDeclarativeTextInputPrivate::focusChanged(bool hasFocus)
+{
+    Q_Q(QDeclarativeTextInput);
+    focused = hasFocus;
+    q->setCursorVisible(hasFocus);
+    if(q->echoMode() == QDeclarativeTextInput::PasswordEchoOnEdit && !hasFocus)
+        control->updatePasswordEchoEditing(false);//QLineControl sets it on key events, but doesn't deal with focus events
+    if (!hasFocus)
+        control->deselect();
+    QDeclarativeItemPrivate::focusChanged(hasFocus);
+}
+
+void QDeclarativeTextInput::keyPressEvent(QKeyEvent* ev)
+{
+    Q_D(QDeclarativeTextInput);
+    keyPressPreHandler(ev);
+    if (ev->isAccepted())
+        return;
+    if (((ev->key() == Qt::Key_Up || ev->key() == Qt::Key_Down) && ev->modifiers() == Qt::NoModifier) // Don't allow MacOSX up/down support, and we don't allow a completer.
+        || (((d->control->cursor() == 0 && ev->key() == Qt::Key_Left)
+            || (d->control->cursor() == d->control->text().length()
+                && ev->key() == Qt::Key_Right))
+            && (d->lastSelectionStart == d->lastSelectionEnd)))
+    {
+        //ignore when moving off the end
+        //unless there is a selection, because then moving will do something (deselect)
+        ev->ignore();
+    }else{
+        d->control->processKeyEvent(ev);
+    }
+    if (!ev->isAccepted())
+        QDeclarativePaintedItem::keyPressEvent(ev);
+}
+
+void QDeclarativeTextInput::mousePressEvent(QGraphicsSceneMouseEvent *event)
+{
+    Q_D(QDeclarativeTextInput);
+    bool hadFocus = hasFocus();
+    if(d->focusOnPress){
+        QGraphicsItem *p = parentItem();//###Is there a better way to find my focus scope?
+        while(p) {
+            if (p->flags() & QGraphicsItem::ItemIsFocusScope)
+                p->setFocus();
+            p = p->parentItem();
+        }
+        setFocus(true);
+    }
+    if (!hadFocus && hasFocus())
+        d->clickCausedFocus = true;
+
+    bool mark = event->modifiers() & Qt::ShiftModifier;
+    int cursor = d->xToPos(event->pos().x());
+    d->control->moveCursor(cursor, mark);
+    event->setAccepted(true);
+}
+
+void QDeclarativeTextInput::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
+{
+    Q_D(QDeclarativeTextInput);
+    if (d->selectByMouse) {
+        d->control->moveCursor(d->xToPos(event->pos().x()), true);
+        event->setAccepted(true);
+    } else {
+        QDeclarativePaintedItem::mouseMoveEvent(event);
+    }
+}
+
+/*!
+\overload
+Handles the given mouse \a event.
+*/
+void QDeclarativeTextInput::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
+{
+    Q_D(QDeclarativeTextInput);
+    QWidget *widget = event->widget();
+    if (widget && !d->control->isReadOnly() && boundingRect().contains(event->pos()))
+        qt_widget_private(widget)->handleSoftwareInputPanel(event->button(), d->clickCausedFocus);
+    d->clickCausedFocus = false;
+    if (!event->isAccepted())
+        QDeclarativePaintedItem::mouseReleaseEvent(event);
+}
+
+bool QDeclarativeTextInput::event(QEvent* ev)
+{
+    Q_D(QDeclarativeTextInput);
+    //Anything we don't deal with ourselves, pass to the control
+    bool handled = false;
+    switch(ev->type()){
+        case QEvent::KeyPress:
+        case QEvent::KeyRelease://###Should the control be doing anything with release?
+        case QEvent::GraphicsSceneMousePress:
+        case QEvent::GraphicsSceneMouseMove:
+        case QEvent::GraphicsSceneMouseRelease:
+            break;
+        default:
+            if (ev->type() == QEvent::GraphicsSceneMouseDoubleClick && !d->selectByMouse)
+                break;
+            handled = d->control->processEvent(ev);
+            if (ev->type() == QEvent::InputMethod)
+                updateSize();
+    }
+    if(!handled)
+        handled = QDeclarativePaintedItem::event(ev);
+    return handled;
+}
+
+void QDeclarativeTextInput::geometryChanged(const QRectF &newGeometry,
+                                  const QRectF &oldGeometry)
+{
+    if (newGeometry.width() != oldGeometry.width())
+        updateSize();
+    QDeclarativePaintedItem::geometryChanged(newGeometry, oldGeometry);
+}
+
+void QDeclarativeTextInput::drawContents(QPainter *p, const QRect &r)
+{
+    Q_D(QDeclarativeTextInput);
+    p->setRenderHint(QPainter::TextAntialiasing, true);
+    p->save();
+    p->setPen(QPen(d->color));
+    int flags = QLineControl::DrawText;
+    if(!isReadOnly() && d->cursorVisible && !d->cursorItem)
+        flags |= QLineControl::DrawCursor;
+    if (d->control->hasSelectedText())
+            flags |= QLineControl::DrawSelections;
+    QPoint offset = QPoint(0,0);
+    QFontMetrics fm = QFontMetrics(d->font);
+    int cix = qRound(d->control->cursorToX());
+    QRect br(boundingRect().toRect());
+    //###Is this using bearing appropriately?
+    int minLB = qMax(0, -fm.minLeftBearing());
+    int minRB = qMax(0, -fm.minRightBearing());
+    int widthUsed = qRound(d->control->naturalTextWidth()) + 1 + minRB;
+    if (d->autoScroll) {
+        if ((minLB + widthUsed) <=  br.width()) {
+            // text fits in br; use hscroll for alignment
+            switch (d->hAlign & ~(Qt::AlignAbsolute|Qt::AlignVertical_Mask)) {
+            case Qt::AlignRight:
+                d->hscroll = widthUsed - br.width() + 1;
+                break;
+            case Qt::AlignHCenter:
+                d->hscroll = (widthUsed - br.width()) / 2;
+                break;
+            default:
+                // Left
+                d->hscroll = 0;
+                break;
+            }
+            d->hscroll -= minLB;
+        } else if (cix - d->hscroll >= br.width()) {
+            // text doesn't fit, cursor is to the right of br (scroll right)
+            d->hscroll = cix - br.width() + 1;
+        } else if (cix - d->hscroll < 0 && d->hscroll < widthUsed) {
+            // text doesn't fit, cursor is to the left of br (scroll left)
+            d->hscroll = cix;
+        } else if (widthUsed - d->hscroll < br.width()) {
+            // text doesn't fit, text document is to the left of br; align
+            // right
+            d->hscroll = widthUsed - br.width() + 1;
+        }
+        // the y offset is there to keep the baseline constant in case we have script changes in the text.
+        offset = br.topLeft() - QPoint(d->hscroll, d->control->ascent() - fm.ascent());
+    } else {
+        if(d->hAlign == AlignRight){
+            d->hscroll = width() - widthUsed;
+        }else if(d->hAlign == AlignHCenter){
+            d->hscroll = (width() - widthUsed) / 2;
+        }
+        d->hscroll -= minLB;
+        offset = QPoint(d->hscroll, 0);
+    }
+
+    d->control->draw(p, offset, r, flags);
+
+    p->restore();
+}
+
+/*!
+\overload
+Returns the value of the given \a property.
+*/
+QVariant QDeclarativeTextInput::inputMethodQuery(Qt::InputMethodQuery property) const
+{
+    Q_D(const QDeclarativeTextInput);
+    switch(property) {
+    case Qt::ImMicroFocus:
+        return d->control->cursorRect();
+    case Qt::ImFont:
+        return font();
+    case Qt::ImCursorPosition:
+        return QVariant(d->control->cursor());
+    case Qt::ImSurroundingText:
+        return QVariant(text());
+    case Qt::ImCurrentSelection:
+        return QVariant(selectedText());
+    case Qt::ImMaximumTextLength:
+        return QVariant(maxLength());
+    case Qt::ImAnchorPosition:
+        if (d->control->selectionStart() == d->control->selectionEnd())
+            return QVariant(d->control->cursor());
+        else if (d->control->selectionStart() == d->control->cursor())
+            return QVariant(d->control->selectionEnd());
+        else
+            return QVariant(d->control->selectionStart());
+    default:
+        return QVariant();
+    }
+}
+
+void QDeclarativeTextInput::selectAll()
+{
+    Q_D(QDeclarativeTextInput);
+    d->control->setSelection(0, d->control->text().length());
+}
+
+
+/*!
+    \qmlproperty bool TextInput::smooth
+
+    This property holds whether the text is smoothly scaled or transformed.
+
+    Smooth filtering gives better visual quality, but is slower.  If
+    the item is displayed at its natural size, this property has no visual or
+    performance effect.
+
+    \note Generally scaling artifacts are only visible if the item is stationary on
+    the screen.  A common pattern when animating an item is to disable smooth
+    filtering at the beginning of the animation and reenable it at the conclusion.
+*/
+
+/*!
+   \qmlproperty string TextInput::passwordCharacter
+
+   This is the character displayed when echoMode is set to Password or
+   PasswordEchoOnEdit. By default it is an asterisk.
+
+   If this property is set to a string with more than one character,
+   the first character is used. If the string is empty, the value
+   is ignored and the property is not set.
+*/
+QString QDeclarativeTextInput::passwordCharacter() const
+{
+    Q_D(const QDeclarativeTextInput);
+    return QString(d->control->passwordCharacter());
+}
+
+void QDeclarativeTextInput::setPasswordCharacter(const QString &str)
+{
+    Q_D(QDeclarativeTextInput);
+    if(str.length() < 1)
+        return;
+    emit passwordCharacterChanged();
+    d->control->setPasswordCharacter(str.constData()[0]);
+}
+
+/*!
+   \qmlproperty string TextInput::displayText
+
+   This is the text displayed in the TextInput.
+
+   If \l echoMode is set to TextInput::Normal, this holds the
+   same value as the TextInput::text property. Otherwise,
+   this property holds the text visible to the user, while
+   the \l text property holds the actual entered text.
+*/
+QString QDeclarativeTextInput::displayText() const
+{
+    Q_D(const QDeclarativeTextInput);
+    return d->control->displayText();
+}
+
+/*!
+    \qmlproperty string TextInput::selectByMouse
+
+    Defaults to false.
+
+    If true, the user can use the mouse to select text in some
+    platform-specific way. Note that for some platforms this may
+    not be an appropriate interaction (eg. may conflict with how
+    the text needs to behave inside a Flickable.
+*/
+bool QDeclarativeTextInput::selectByMouse() const
+{
+    Q_D(const QDeclarativeTextInput);
+    return d->selectByMouse;
+}
+
+void QDeclarativeTextInput::setSelectByMouse(bool on)
+{
+    Q_D(QDeclarativeTextInput);
+    if (d->selectByMouse != on) {
+        d->selectByMouse = on;
+        emit selectByMouseChanged(on);
+    }
+}
+
+
+/*!
+    \qmlmethod void TextInput::moveCursorSelection(int position)
+
+    Moves the cursor to \a position and updates the selection accordingly.
+    (To only move the cursor, set the \l cursorPosition property.)
+
+    When this method is called it additionally sets either the
+    selectionStart or the selectionEnd (whichever was at the previous cursor position)
+    to the specified position. This allows you to easily extend and contract the selected
+    text range.
+
+    For example, take this sequence of calls:
+
+    \code
+        cursorPosition = 5
+        moveCursorSelection(9)
+        moveCursorSelection(7)
+    \endcode
+
+    This moves the cursor to position 5, extend the selection end from 5 to 9
+    and then retract the selection end from 9 to 7, leaving the text from position 5 to 7
+    selected (the 6th and 7th characters).
+*/
+void QDeclarativeTextInput::moveCursorSelection(int position)
+{
+    Q_D(QDeclarativeTextInput);
+    d->control->moveCursor(position, true);
+}
+
+void QDeclarativeTextInputPrivate::init()
+{
+    Q_Q(QDeclarativeTextInput);
+    control->setCursorWidth(1);
+    control->setPasswordCharacter(QLatin1Char('*'));
+    control->setLayoutDirection(Qt::LeftToRight);
+    q->setSmooth(smooth);
+    q->setAcceptedMouseButtons(Qt::LeftButton);
+    q->setFlag(QGraphicsItem::ItemHasNoContents, false);
+    q->setFlag(QGraphicsItem::ItemAcceptsInputMethod);
+    q->connect(control, SIGNAL(cursorPositionChanged(int,int)),
+               q, SLOT(cursorPosChanged()));
+    q->connect(control, SIGNAL(selectionChanged()),
+               q, SLOT(selectionChanged()));
+    q->connect(control, SIGNAL(textChanged(const QString &)),
+               q, SIGNAL(displayTextChanged(const QString &)));
+    q->connect(control, SIGNAL(textChanged(const QString &)),
+               q, SLOT(q_textChanged()));
+    q->connect(control, SIGNAL(accepted()),
+               q, SIGNAL(accepted()));
+    q->connect(control, SIGNAL(updateNeeded(QRect)),
+               q, SLOT(updateRect(QRect)));
+    q->connect(control, SIGNAL(cursorPositionChanged(int,int)),
+               q, SLOT(updateRect()));//TODO: Only update rect between pos's
+    q->connect(control, SIGNAL(selectionChanged()),
+               q, SLOT(updateRect()));//TODO: Only update rect in selection
+    //Note that above TODOs probably aren't that big a savings
+    q->updateSize();
+    oldValidity = control->hasAcceptableInput();
+    lastSelectionStart = 0;
+    lastSelectionEnd = 0;
+    QPalette p = control->palette();
+    selectedTextColor = p.color(QPalette::HighlightedText);
+    selectionColor = p.color(QPalette::Highlight);
+}
+
+void QDeclarativeTextInput::cursorPosChanged()
+{
+    Q_D(QDeclarativeTextInput);
+    emit cursorPositionChanged();
+
+    if(!d->control->hasSelectedText()){
+        if(d->lastSelectionStart != d->control->cursor()){
+            d->lastSelectionStart = d->control->cursor();
+            emit selectionStartChanged();
+        }
+        if(d->lastSelectionEnd != d->control->cursor()){
+            d->lastSelectionEnd = d->control->cursor();
+            emit selectionEndChanged();
+        }
+    }
+}
+
+void QDeclarativeTextInput::selectionChanged()
+{
+    Q_D(QDeclarativeTextInput);
+    emit selectedTextChanged();
+
+    if(d->lastSelectionStart != d->control->selectionStart()){
+        d->lastSelectionStart = d->control->selectionStart();
+        if(d->lastSelectionStart == -1)
+            d->lastSelectionStart = d->control->cursor();
+        emit selectionStartChanged();
+    }
+    if(d->lastSelectionEnd != d->control->selectionEnd()){
+        d->lastSelectionEnd = d->control->selectionEnd();
+        if(d->lastSelectionEnd == -1)
+            d->lastSelectionEnd = d->control->cursor();
+        emit selectionEndChanged();
+    }
+}
+
+void QDeclarativeTextInput::q_textChanged()
+{
+    Q_D(QDeclarativeTextInput);
+    updateSize();
+    emit textChanged();
+    if(hasAcceptableInput() != d->oldValidity){
+        d->oldValidity = hasAcceptableInput();
+        emit acceptableInputChanged();
+    }
+}
+
+void QDeclarativeTextInput::updateRect(const QRect &r)
+{
+    Q_D(QDeclarativeTextInput);
+    if(r == QRect())
+        clearCache();
+    else
+        dirtyCache(QRect(r.x() - d->hscroll, r.y(), r.width(), r.height()));
+    update();
+}
+
+void QDeclarativeTextInput::updateSize(bool needsRedraw)
+{
+    Q_D(QDeclarativeTextInput);
+    int w = width();
+    int h = height();
+    setImplicitHeight(d->control->height());
+    int cursorWidth = d->control->cursorWidth();
+    if(d->cursorItem)
+        cursorWidth = d->cursorItem->width();
+    setImplicitWidth(d->control->naturalTextWidth() + cursorWidth);
+    setContentsSize(QSize(width(), height()));//Repaints if changed
+    if(w==width() && h==height() && needsRedraw){
+        clearCache();
+        update();
+    }
+}
+
+QT_END_NAMESPACE
+